Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 3 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -78,37 +78,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),
}
Loading