Skip to content

Commit

Permalink
Check supertraits and gen args when resolving anon consts in assoc co…
Browse files Browse the repository at this point in the history
…nst eq bounds
  • Loading branch information
fmease committed Nov 27, 2023
1 parent a191610 commit 4c0addc
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 23 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// type itself: `['a]`. The returned `GenericArgsRef` concatenates these two
/// lists: `[Vec<u8>, u8, 'a]`.
#[instrument(level = "debug", skip(self, span), ret)]
fn create_args_for_ast_path<'a>(
pub(crate) fn create_args_for_ast_path<'a>(
&self,
span: Span,
def_id: DefId,
Expand Down
87 changes: 65 additions & 22 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::symbol::Ident;
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits;

use super::ItemCtxt;
use super::{bad_placeholder, is_suggestable_infer_ty};
use super::{AstConv, ItemCtxt};
pub use opaque::test_opaque_hidden_types;

mod opaque;
Expand Down Expand Up @@ -60,35 +61,78 @@ 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.hir().get(tcx.hir().parent_id(binding_id)) =>
{
Node::TypeBinding(
binding @ &TypeBinding { hir_id: binding_id, ident, gen_args, span, .. },
) if let Node::TraitRef(trait_ref) = tcx.hir().get(tcx.hir().parent_id(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",
"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(),

// FIXME(associated_const_equality): We're now performing a full but ad-hoc type-based
// resolution of the associated constant. Doing all this work *here* isn't great.
// Ideally, we would've computed this already somewhere else (in a query?).

let icx = ItemCtxt::new(tcx, def_id);
let trait_segment = trait_ref.path.segments.last().unwrap();
let (trait_args, _) = icx.astconv().create_args_for_ast_path(
trait_ref.path.span,
trait_def_id,
&[],
trait_segment,
trait_segment.args(),
trait_segment.infer_args,
// FIXME(associated_const_equality): This isn't correct, it should be the concrete /
// instantiated self type. Theoretically, we could search for it in the HIR of the
// parent item but that's super fragile and hairy.
Some(tcx.types.self_param),
ty::BoundConstness::NotConst,
);
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(
let trait_ref = ty::Binder::bind_with_vars(
ty::TraitRef::new(tcx, trait_def_id, trait_args),
tcx.late_bound_vars(trait_ref.hir_ref_id),
);

// We shouldn't need to deal with ambiguity since `add_predicates_for_ast_type_binding`
// should've already bailed out early in such case.
let Some((assoc_item, parent_args)) =
traits::supertraits(tcx, trait_ref).find_map(|trait_ref| {
tcx.associated_items(trait_ref.def_id())
.find_by_name_and_kind(
tcx,
binding.ident,
ty::AssocKind::Const,
trait_ref.def_id(),
)
// FIXME(fmease): `skip_binder` is fishy!
.map(|item| (item, trait_ref.skip_binder().args))
})
else {
return Ty::new_error_with_message(
tcx,
tcx.def_span(def_id),
"Could not find associated const on trait",
)
"could not find associated const on trait",
);
};

let args = icx.astconv().create_args_for_associated_item(
span,
assoc_item.def_id,
// FIXME(fmease): This is gross as hell!
&hir::PathSegment {
ident,
hir_id,
res: def::Res::Def(def::DefKind::AssocConst, assoc_item.def_id),
args: Some(gen_args),
infer_args: false,
},
parent_args,
);

return tcx.type_of(assoc_item.def_id).instantiate(tcx, args);
}

// This match arm is for when the def_id appears in a GAT whose
Expand Down Expand Up @@ -120,8 +164,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
.unwrap()
.0
.def_id;
let item_ctxt = &ItemCtxt::new(tcx, item_def_id) as &dyn crate::astconv::AstConv<'_>;
let ty = item_ctxt.ast_ty_to_ty(hir_ty);
let ty = ItemCtxt::new(tcx, item_def_id).to_ty(hir_ty);

// Iterate through the generics of the projection to find the one that corresponds to
// the def_id that this query was called with. We filter to only type and const args here
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() {}
3 changes: 3 additions & 0 deletions tests/ui/generic-const-items/associated-const-equality.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
trait Owner {
const C<const N: u32>: u32;
const K<const N: u32>: u32;
const Q<T>: Option<T>;
}

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

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

fn main() {
take0::<128>(());
Expand Down

0 comments on commit 4c0addc

Please sign in to comment.