diff options
| author | bors <bors@rust-lang.org> | 2024-12-14 10:22:43 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-12-14 10:22:43 +0000 |
| commit | f5079d00e63718235f95353df38ebb0891bab5b4 (patch) | |
| tree | a6900feb1a5792511b8ec4573d8e391b122410ee /compiler/rustc_hir_analysis/src | |
| parent | ed141926048597e3649bb238ca3dc417904cd56c (diff) | |
| parent | d714a22e7bc38b158d09ee6294d1716acd1a727d (diff) | |
| download | rust-f5079d00e63718235f95353df38ebb0891bab5b4.tar.gz rust-f5079d00e63718235f95353df38ebb0891bab5b4.zip | |
Auto merge of #134185 - compiler-errors:impl-trait-in-bindings, r=oli-obk
(Re-)Implement `impl_trait_in_bindings`
This reimplements the `impl_trait_in_bindings` feature for local bindings.
"`impl Trait` in bindings" serve as a form of *trait* ascription, where the type basically functions as an infer var but additionally registering the `impl Trait`'s trait bounds for the infer type. These trait bounds can be used to enforce that predicates hold, and can guide inference (e.g. for closure signature inference):
```rust
let _: impl Fn(&u8) -> &u8 = |x| x;
```
They are implemented as an additional set of bounds that are registered when the type is lowered during typeck, and then these bounds are tied to a given `CanonicalUserTypeAscription` for borrowck. We enforce these `CanonicalUserTypeAscription` bounds during borrowck to make sure that the `impl Trait` types are sensitive to lifetimes:
```rust
trait Static: 'static {}
impl<T> Static for T where T: 'static {}
let local = 1;
let x: impl Static = &local;
//~^ ERROR `local` does not live long enough
```
r? oli-obk
cc #63065
---
Why can't we just use TAIT inference or something? Well, TAITs in bodies have the problem that they cannot reference lifetimes local to a body. For example:
```rust
type TAIT = impl Display;
let local = 0;
let x: TAIT = &local;
//~^ ERROR `local` does not live long enough
```
That's because TAITs requires us to do *opaque type inference* which is pretty strict, since we need to remap all of the lifetimes of the hidden type to universal regions. This is simply not possible here.
---
I consider this part of the "impl trait everywhere" experiment. I'm not certain if this needs yet another lang team experiment.
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
| -rw-r--r-- | compiler/rustc_hir_analysis/src/collect.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs | 26 |
3 files changed, 51 insertions, 1 deletions
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index cb5086c9a65..7fb024cce5a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -29,7 +29,7 @@ use rustc_errors::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor, walk_generics}; -use rustc_hir::{self as hir, GenericParamKind, Node}; +use rustc_hir::{self as hir, GenericParamKind, HirId, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; @@ -437,6 +437,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant") } + fn register_trait_ascription_bounds( + &self, + _: Vec<(ty::Clause<'tcx>, Span)>, + _: HirId, + span: Span, + ) { + self.dcx().span_delayed_bug(span, "trait ascription type not allowed here"); + } + fn probe_ty_param_bounds( &self, span: Span, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 923d2b1fe67..0f797bcdae4 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -852,6 +852,21 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }; self.with(scope, |this| this.visit_ty(mt.ty)); } + hir::TyKind::TraitAscription(bounds) => { + let scope = Scope::TraitRefBoundary { s: self.scope }; + self.with(scope, |this| { + let scope = Scope::LateBoundary { + s: this.scope, + what: "`impl Trait` in binding", + deny_late_regions: true, + }; + this.with(scope, |this| { + for bound in bounds { + this.visit_param_bound(bound); + } + }) + }); + } _ => intravisit::walk_ty(self, ty), } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1bdbde30037..a357ade0294 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -123,6 +123,13 @@ pub trait HirTyLowerer<'tcx> { /// Returns the const to use when a const is omitted. fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>; + fn register_trait_ascription_bounds( + &self, + bounds: Vec<(ty::Clause<'tcx>, Span)>, + hir_id: HirId, + span: Span, + ); + /// Probe bounds in scope where the bounded type coincides with the given type parameter. /// /// Rephrased, this returns bounds of the form `T: Trait`, where `T` is a type parameter @@ -2375,6 +2382,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.lower_opaque_ty(opaque_ty.def_id, in_trait) } + hir::TyKind::TraitAscription(hir_bounds) => { + // Impl trait in bindings lower as an infer var with additional + // set of type bounds. + let self_ty = self.ty_infer(None, hir_ty.span); + let mut bounds = Bounds::default(); + self.lower_bounds( + self_ty, + hir_bounds.iter(), + &mut bounds, + ty::List::empty(), + PredicateFilter::All, + ); + self.register_trait_ascription_bounds( + bounds.clauses().collect(), + hir_ty.hir_id, + hir_ty.span, + ); + self_ty + } // If we encounter a type relative path with RTN generics, then it must have // *not* gone through `lower_ty_maybe_return_type_notation`, and therefore // it's certainly in an illegal position. |
