1
Fork 0

Rollup merge of #120719 - compiler-errors:no-dyn-atb, r=lcnr

Remove support for `associated_type_bound` nested in `dyn` types

These necessarily desugar to `impl Trait`, which is inconsistent with the `associated_type_bound` feature after #120584.

This PR keeps the `is_in_dyn_type` hack, which kind of makes me sad. Ideally, we'd be validating that no object types have associated type bounds somewhere else. Unfortunately, we can't do this later during astconv (i think?), nor can we do it earlier during ast validation (i think?) because of the feature gating of ATB being a *warning* rather than an *error*. Let me know if you have thoughts about this.

r? lcnr
This commit is contained in:
Matthias Krüger 2024-02-10 13:12:28 +01:00 committed by GitHub
commit e11e4446da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 91 additions and 429 deletions

View file

@ -8,6 +8,10 @@ ast_lowering_arbitrary_expression_in_pattern =
ast_lowering_argument = argument
ast_lowering_assoc_ty_binding_in_dyn =
associated type bounds are not allowed in `dyn` types
.suggestion = use `impl Trait` to introduce a type instead
ast_lowering_assoc_ty_parentheses =
parenthesized generic arguments cannot be used in associated type constraints
@ -100,9 +104,6 @@ ast_lowering_match_arm_with_no_body =
`match` arm with no body
.suggestion = add a body after the pattern
ast_lowering_misplaced_assoc_ty_binding =
associated type bounds are only allowed in where clauses and function signatures, not in {$position}
ast_lowering_misplaced_double_dot =
`..` patterns are not allowed here
.note = only allowed in tuple, tuple struct, and slice patterns

View file

@ -94,11 +94,12 @@ pub struct MisplacedImplTrait<'a> {
}
#[derive(Diagnostic)]
#[diag(ast_lowering_misplaced_assoc_ty_binding)]
pub struct MisplacedAssocTyBinding<'a> {
#[diag(ast_lowering_assoc_ty_binding_in_dyn)]
pub struct MisplacedAssocTyBinding {
#[primary_span]
pub span: Span,
pub position: DiagnosticArgFromDisplay<'a>,
#[suggestion(code = " = impl", applicability = "maybe-incorrect", style = "verbose")]
pub suggestion: Option<Span>,
}
#[derive(Diagnostic, Clone, Copy)]

View file

@ -197,7 +197,6 @@ trait ResolverAstLoweringExt {
fn get_label_res(&self, id: NodeId) -> Option<NodeId>;
fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
fn remap_extra_lifetime_params(&mut self, from: NodeId, to: NodeId);
}
impl ResolverAstLoweringExt for ResolverAstLowering {
@ -256,11 +255,6 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)> {
self.extra_lifetime_params_map.remove(&id).unwrap_or_default()
}
fn remap_extra_lifetime_params(&mut self, from: NodeId, to: NodeId) {
let lifetimes = self.extra_lifetime_params_map.remove(&from).unwrap_or_default();
self.extra_lifetime_params_map.insert(to, lifetimes);
}
}
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
@ -1084,88 +1078,38 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::TypeBindingKind::Equality { term }
}
AssocConstraintKind::Bound { bounds } => {
enum DesugarKind {
ImplTrait,
Error(ImplTraitPosition),
Bound,
}
// Disallow ATB in dyn types
if self.is_in_dyn_type {
let suggestion = match itctx {
ImplTraitContext::ReturnPositionOpaqueTy { .. }
| ImplTraitContext::TypeAliasesOpaqueTy { .. }
| ImplTraitContext::Universal => {
let bound_end_span = constraint
.gen_args
.as_ref()
.map_or(constraint.ident.span, |args| args.span());
if bound_end_span.eq_ctxt(constraint.span) {
Some(self.tcx.sess.source_map().next_point(bound_end_span))
} else {
None
}
}
_ => None,
};
// Piggy-back on the `impl Trait` context to figure out the correct behavior.
let desugar_kind = match itctx {
// in an argument, RPIT, or TAIT, if we are within a dyn type:
//
// fn foo(x: dyn Iterator<Item: Debug>)
//
// then desugar to:
//
// fn foo(x: dyn Iterator<Item = impl Debug>)
//
// This is because dyn traits must have all of their associated types specified.
ImplTraitContext::ReturnPositionOpaqueTy { .. }
| ImplTraitContext::TypeAliasesOpaqueTy { .. }
| ImplTraitContext::Universal
if self.is_in_dyn_type =>
{
DesugarKind::ImplTrait
}
let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding {
span: constraint.span,
suggestion,
});
let err_ty =
&*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
hir::TypeBindingKind::Equality { term: err_ty.into() }
} else {
// Desugar `AssocTy: Bounds` into a type binding where the
// later desugars into a trait predicate.
let bounds = self.lower_param_bounds(bounds, itctx);
ImplTraitContext::Disallowed(position) if self.is_in_dyn_type => {
DesugarKind::Error(position)
}
// We are in the parameter position, but not within a dyn type:
//
// fn foo(x: impl Iterator<Item: Debug>)
//
// so we leave it as is and this gets expanded in astconv to a bound like
// `<T as Iterator>::Item: Debug` where `T` is the type parameter for the
// `impl Iterator`.
_ => DesugarKind::Bound,
};
match desugar_kind {
DesugarKind::ImplTrait => {
// Desugar `AssocTy: Bounds` into `AssocTy = impl Bounds`. We do this by
// constructing the HIR for `impl bounds...` and then lowering that.
let impl_trait_node_id = self.next_node_id();
// Shift `impl Trait` lifetime captures from the associated type bound's
// node id to the opaque node id, so that the opaque can actually use
// these lifetime bounds.
self.resolver
.remap_extra_lifetime_params(constraint.id, impl_trait_node_id);
self.with_dyn_type_scope(false, |this| {
let node_id = this.next_node_id();
let ty = this.lower_ty(
&Ty {
id: node_id,
kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
span: this.lower_span(constraint.span),
tokens: None,
},
itctx,
);
hir::TypeBindingKind::Equality { term: ty.into() }
})
}
DesugarKind::Bound => {
// Desugar `AssocTy: Bounds` into a type binding where the
// later desugars into a trait predicate.
let bounds = self.lower_param_bounds(bounds, itctx);
hir::TypeBindingKind::Constraint { bounds }
}
DesugarKind::Error(position) => {
let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding {
span: constraint.span,
position: DiagnosticArgFromDisplay(&position),
});
let err_ty =
&*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
hir::TypeBindingKind::Equality { term: err_ty.into() }
}
hir::TypeBindingKind::Constraint { bounds }
}
}
};