This commit is contained in:
Michael Goulet 2023-03-05 01:08:17 +00:00
parent fb9ca9223d
commit 773e8a5ad1
3 changed files with 120 additions and 51 deletions

View File

@ -987,8 +987,20 @@ fn lower_assoc_ty_constraint(
GenericArgs::AngleBracketed(data) => {
self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
}
GenericArgs::Parenthesized(data)
if self.tcx.features().return_type_notation =>
{
// TODO: Check the parens + no return type
GenericArgsCtor {
args: Default::default(),
bindings: &[],
parenthesized: true,
span: data.span,
}
}
GenericArgs::Parenthesized(data) => {
self.emit_bad_parenthesized_trait_in_assoc_ty(data);
// TODO: Add a RTN feature error if the parens are shaped correctly
self.lower_angle_bracketed_parameter_data(
&data.as_angle_bracketed_args(),
ParamMode::Explicit,

View File

@ -854,16 +854,15 @@ fn create_substs_for_ast_trait_ref<'a>(
)
}
fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
fn trait_defines_associated_item_named(
&self,
trait_def_id: DefId,
assoc_kind: ty::AssocKind,
assoc_name: Ident,
) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
.is_some()
}
fn trait_defines_associated_const_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
self.tcx()
.associated_items(trait_def_id)
.find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Const, trait_def_id)
.find_by_name_and_kind(self.tcx(), assoc_name, assoc_kind, trait_def_id)
.is_some()
}
@ -1087,24 +1086,42 @@ fn add_predicates_for_ast_type_binding(
let tcx = self.tcx();
let candidate =
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
// Simple case: X is defined in the current trait.
// TODO: rtn comment goes here
let associated_return_type_bound =
binding.gen_args.parenthesized && self.tcx().features().associated_return_type_bounds;
let candidate = if return_type_notation {
if self.trait_defines_associated_item_named(
trait_ref.def_id(),
ty::AssocKind::Fn,
binding.item_name,
) {
trait_ref
} else {
// Otherwise, we have to walk through the supertraits to find
// those that do.
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, trait_ref),
trait_ref.print_only_trait_path(),
binding.item_name,
path_span,
match binding.kind {
ConvertedBindingKind::Equality(term) => Some(term),
_ => None,
},
)?
};
// TODO: error
todo!()
}
} else if self.trait_defines_associated_item_named(
trait_ref.def_id(),
ty::AssocKind::Type,
binding.item_name,
) {
// Simple case: X is defined in the current trait.
trait_ref
} else {
// Otherwise, we have to walk through the supertraits to find
// those that do.
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, trait_ref),
trait_ref.print_only_trait_path(),
binding.item_name,
path_span,
match binding.kind {
ConvertedBindingKind::Equality(term) => Some(term),
_ => None,
},
)?
};
let (assoc_ident, def_scope) =
tcx.adjust_ident_and_get_scope(binding.item_name, candidate.def_id(), hir_ref_id);
@ -1116,9 +1133,13 @@ fn add_predicates_for_ast_type_binding(
.filter_by_name_unhygienic(assoc_ident.name)
.find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
};
let assoc_item = find_item_of_kind(ty::AssocKind::Type)
.or_else(|| find_item_of_kind(ty::AssocKind::Const))
.expect("missing associated type");
let assoc_item = if return_type_notation {
find_item_of_kind(ty::AssocKind::Fn)
} else {
find_item_of_kind(ty::AssocKind::Type)
.or_else(|| find_item_of_kind(ty::AssocKind::Const))
}
.expect("missing associated type");
if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
tcx.sess
@ -1145,28 +1166,54 @@ fn add_predicates_for_ast_type_binding(
.or_insert(binding.span);
}
// Include substitutions for generic parameters of associated types
let projection_ty = candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {
ident,
hir_id: binding.hir_id,
res: Res::Err,
args: Some(binding.gen_args),
infer_args: false,
let projection_ty = if associated_return_type_bound {
let generics = self.tcx().generics_of(assoc_item.def_id);
if !generics.params.is_empty() {
todo!();
}
let output = self.tcx().fn_sig(assoc_item.def_id).skip_binder().output();
let fn_bound_vars = output.bound_vars();
let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
&& tcx.def_kind(alias_ty.def_id) == DefKind::ImplTraitPlaceholder
{
alias_ty
} else {
todo!("found return type of {output:?}");
};
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
path_span,
assoc_item.def_id,
&item_segment,
trait_ref.substs,
);
let trait_bound_vars = candidate.bound_vars();
let shifted_output = tcx.shift_bound_var_indices(trait_bound_vars.len(), output);
let subst_output =
ty::EarlyBinder(shifted_output).subst(tcx, candidate.skip_binder().substs);
let bound_vars =
tcx.mk_bound_variable_kinds_from_iter(trait_bound_vars.iter().chain(fn_bound_vars));
debug!(?substs_trait_ref_and_assoc_item);
ty::Binder::bind_with_vars(subst_output, bound_vars)
} else {
// Include substitutions for generic parameters of associated types
candidate.map_bound(|trait_ref| {
let ident = Ident::new(assoc_item.name, binding.item_name.span);
let item_segment = hir::PathSegment {
ident,
hir_id: binding.hir_id,
res: Res::Err,
args: Some(binding.gen_args),
infer_args: false,
};
self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
});
let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
path_span,
assoc_item.def_id,
&item_segment,
trait_ref.substs,
);
debug!(?substs_trait_ref_and_assoc_item);
self.tcx().mk_alias_ty(assoc_item.def_id, substs_trait_ref_and_assoc_item)
})
};
if !speculative {
// Find any late-bound regions declared in `ty` that are not
@ -1206,6 +1253,10 @@ fn add_predicates_for_ast_type_binding(
}
match binding.kind {
ConvertedBindingKind::Equality(..) if associated_return_type_bound => {
// TODO: error
todo!()
}
ConvertedBindingKind::Equality(mut term) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
// the "projection predicate" for:
@ -1267,7 +1318,7 @@ fn add_predicates_for_ast_type_binding(
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
self.add_bounds(param_ty, ast_bounds.iter(), bounds, candidate.bound_vars());
self.add_bounds(param_ty, ast_bounds.iter(), bounds, projection_ty.bound_vars());
}
}
Ok(())
@ -1808,10 +1859,12 @@ fn one_bound_for_assoc_type<I>(
where
I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
{
let mut matching_candidates = all_candidates()
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
let mut const_candidates = all_candidates()
.filter(|r| self.trait_defines_associated_const_named(r.def_id(), assoc_name));
let mut matching_candidates = all_candidates().filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Type, assoc_name)
});
let mut const_candidates = all_candidates().filter(|r| {
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
});
let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
(Some(bound), _) => (bound, matching_candidates.next()),

View File

@ -550,7 +550,11 @@ fn parse_angle_arg(
// Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
if let AssocConstraintKind::Bound { .. } = kind {
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
if gen_args.as_ref().map_or(false, |args| args.is_parenthesized()) {
self.sess.gated_spans.gate(sym::return_type_notation, span);
} else {
self.sess.gated_spans.gate(sym::associated_type_bounds, span);
}
}
let constraint =
AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };