Skip to content

Commit

Permalink
Rollup merge of rust-lang#119385 - fmease:assoc-const-eq-fixes-2, r=o…
Browse files Browse the repository at this point in the history
…li-obk,cjgillot

Fix type resolution of associated const equality bounds (take 2)

Instead of trying to re-resolve the type of assoc const bindings inside the `type_of` query impl in an incomplete manner, transfer the already (correctly) resolved type from `add_predicates_for_ast_type_binding` to `type_of`/`anon_type_of` through query feeding.

---

Together with rust-lang#118668 (merged) and rust-lang#121258, this supersedes rust-lang#118360.
Fixes rust-lang#118040.

r? `@ghost`
  • Loading branch information
matthiaskrgr authored Mar 11, 2024
2 parents 8f33766 + 858d336 commit ccbeb90
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 40 deletions.
22 changes: 20 additions & 2 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
// Create the generic arguments for the associated type or constant by joining the
// parent arguments (the arguments of the trait) and the own arguments (the ones of
// the associated item itself) and construct an alias type using them.
candidate.map_bound(|trait_ref| {
let alias_ty = candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.ident.span);
let item_segment = hir::PathSegment {
ident,
Expand All @@ -430,7 +430,25 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
// *constants* to represent *const projections*. Alias *term* would be a more
// appropriate name but alas.
ty::AliasTy::new(tcx, assoc_item.def_id, alias_args)
})
});

// Provide the resolved type of the associated constant to `type_of(AnonConst)`.
if !speculative
&& let hir::TypeBindingKind::Equality { term: hir::Term::Const(anon_const) } =
binding.kind
{
let ty = alias_ty.map_bound(|ty| tcx.type_of(ty.def_id).instantiate(tcx, ty.args));
// Since the arguments passed to the alias type above may contain early-bound
// generic parameters, the instantiated type may contain some as well.
// Therefore wrap it in `EarlyBinder`.
// FIXME(fmease): Reject escaping late-bound vars.
tcx.feed_anon_const_type(
anon_const.def_id,
ty::EarlyBinder::bind(ty.skip_binder()),
);
}

alias_ty
};

match binding.kind {
Expand Down
31 changes: 0 additions & 31 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,37 +79,6 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
.expect("const parameter types cannot be generic");
}

Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
if let Node::TraitRef(trait_ref) = tcx.parent_hir_node(binding_id) =>
{
let Some(trait_def_id) = trait_ref.trait_def_id() else {
return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id),
"Could not find trait",
);
};
let assoc_items = tcx.associated_items(trait_def_id);
let assoc_item = assoc_items.find_by_name_and_kind(
tcx,
binding.ident,
ty::AssocKind::Const,
def_id.to_def_id(),
);
return if let Some(assoc_item) = assoc_item {
tcx.type_of(assoc_item.def_id)
.no_bound_vars()
.expect("const parameter types cannot be generic")
} else {
// FIXME(associated_const_equality): add a useful error message here.
Ty::new_error_with_message(
tcx,
tcx.def_span(def_id),
"Could not find associated const on trait",
)
};
}

// This match arm is for when the def_id appears in a GAT whose
// path can't be resolved without typechecking e.g.
//
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/associated-consts/assoc-const-eq-supertraits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Regression test for issue #118040.
// Ensure that we support assoc const eq bounds where the assoc const comes from a supertrait.

//@ check-pass

#![feature(associated_const_equality)]

trait Trait: SuperTrait {}
trait SuperTrait: SuperSuperTrait<i32> {}
trait SuperSuperTrait<T> {
const K: T;
}

fn take(_: impl Trait<K = 0>) {}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
// Regression test for issue #112560.
// Respect the fact that (associated) types and constants live in different namespaces and
// therefore equality bounds involving identically named associated items don't conflict if
// their kind (type vs. const) differs.

// FIXME(fmease): Extend this test to cover supertraits again
// once #118040 is fixed. See initial version of PR #118360.
// their kind (type vs. const) differs. This obviously extends to supertraits.

//@ check-pass

#![feature(associated_const_equality)]

trait Trait {
trait Trait: SuperTrait {
type N;
type Q;

const N: usize;
}

fn take(_: impl Trait<N = 0, N = ()>) {}
trait SuperTrait {
const Q: &'static str;
}

fn take0(_: impl Trait<N = 0, N = ()>) {}

fn take1(_: impl Trait<Q = "...", Q = [()]>) {}

fn main() {}
11 changes: 10 additions & 1 deletion tests/ui/generic-const-items/associated-const-equality.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
//@ check-pass

#![feature(generic_const_items, associated_const_equality)]
#![feature(generic_const_items, associated_const_equality, adt_const_params)]
#![allow(incomplete_features)]

trait Owner {
const C<const N: u32>: u32;
const K<const N: u32>: u32;
const Q<T>: Maybe<T>;
}

impl Owner for () {
const C<const N: u32>: u32 = N;
const K<const N: u32>: u32 = N + 1;
const Q<T>: Maybe<T> = Maybe::Nothing;
}

fn take0<const N: u32>(_: impl Owner<C<N> = { N }>) {}
fn take1(_: impl Owner<K<99> = 100>) {}
fn take2(_: impl Owner<Q<()> = { Maybe::Just(()) }>) {}

fn main() {
take0::<128>(());
take1(());
}

#[derive(PartialEq, Eq, std::marker::ConstParamTy)]
enum Maybe<T> {
Nothing,
Just(T),
}

0 comments on commit ccbeb90

Please sign in to comment.