Skip to content

Commit d4096e0

Browse files
committed
Auto merge of #112652 - oli-obk:tait_only_in_sig, r=compiler-errors
Require TAITs to be mentioned in the signatures of functions that register hidden types for them r? `@lcnr` `@compiler-errors` This implements the lang team decision from [the TAIT design meeting](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/design.20meeting.202023-05-31.20TAITs/near/362518164).
2 parents eee6b31 + c3004a7 commit d4096e0

File tree

76 files changed

+781
-189
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+781
-189
lines changed

Diff for: compiler/rustc_error_messages/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ fn register_functions(bundle: &mut FluentBundle) {
226226
pub type LazyFallbackBundle = Lrc<Lazy<FluentBundle, impl FnOnce() -> FluentBundle>>;
227227

228228
/// Return the default `FluentBundle` with standard "en-US" diagnostic messages.
229-
#[instrument(level = "trace")]
229+
#[instrument(level = "trace", skip(resources))]
230230
pub fn fallback_fluent_bundle(
231231
resources: Vec<&'static str>,
232232
with_directionality_markers: bool,
@@ -242,7 +242,6 @@ pub fn fallback_fluent_bundle(
242242
for resource in resources {
243243
let resource = FluentResource::try_new(resource.to_string())
244244
.expect("failed to parse fallback fluent resource");
245-
trace!(?resource);
246245
fallback_bundle.add_resource_overriding(resource);
247246
}
248247

Diff for: compiler/rustc_hir_analysis/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ hir_analysis_static_specialize = cannot specialize on `'static` lifetime
248248
249249
hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
250250
251+
hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature
252+
.note = this item must mention the opaque type in its signature in order to be able to register hidden types
253+
251254
hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
252255
253256
hir_analysis_too_large_static = extern static is too large for the current architecture

Diff for: compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_middle::hir::nested_filter;
66
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
77
use rustc_span::DUMMY_SP;
88

9-
use crate::errors::UnconstrainedOpaqueType;
9+
use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType};
1010

1111
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
1212
/// laid for "higher-order pattern unification".
@@ -139,6 +139,15 @@ impl TaitConstraintLocator<'_> {
139139
continue;
140140
}
141141
constrained = true;
142+
if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) {
143+
self.tcx.sess.emit_err(TaitForwardCompat {
144+
span: hidden_type.span,
145+
item_span: self
146+
.tcx
147+
.def_ident_span(item_def_id)
148+
.unwrap_or_else(|| self.tcx.def_span(item_def_id)),
149+
});
150+
}
142151
let concrete_type =
143152
self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params(
144153
opaque_type_key,

Diff for: compiler/rustc_hir_analysis/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,16 @@ pub struct UnconstrainedOpaqueType {
184184
pub what: &'static str,
185185
}
186186

187+
#[derive(Diagnostic)]
188+
#[diag(hir_analysis_tait_forward_compat)]
189+
#[note]
190+
pub struct TaitForwardCompat {
191+
#[primary_span]
192+
pub span: Span,
193+
#[note]
194+
pub item_span: Span,
195+
}
196+
187197
pub struct MissingTypeParams {
188198
pub span: Span,
189199
pub def_span: Span,

Diff for: compiler/rustc_hir_typeck/src/inherited.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl<'tcx> Inherited<'tcx> {
8080
let infcx = tcx
8181
.infer_ctxt()
8282
.ignoring_regions()
83-
.with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id))
83+
.with_opaque_type_inference(DefiningAnchor::Bind(def_id))
8484
.build();
8585
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
8686

Diff for: compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ impl<T> Trait<T> for X {
257257
);
258258
}
259259
}
260-
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => {
260+
(ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::Fn | DefKind::Static(_) | DefKind::Const | DefKind::AssocFn | DefKind::AssocConst) => {
261261
if tcx.is_type_alias_impl_trait(alias.def_id) {
262262
if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
263263
let sp = tcx.def_ident_span(body_owner_def_id).unwrap_or_else(|| tcx.def_span(body_owner_def_id));

Diff for: compiler/rustc_trait_selection/src/traits/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ mod fulfill;
1111
pub mod misc;
1212
mod object_safety;
1313
pub mod outlives_bounds;
14-
mod project;
14+
pub mod project;
1515
pub mod query;
1616
#[cfg_attr(not(bootstrap), allow(hidden_glob_reexports))]
1717
mod select;

Diff for: compiler/rustc_ty_utils/src/opaque_types.rs

+117-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use rustc_data_structures::fx::FxHashSet;
2+
use rustc_hir::intravisit::Visitor;
23
use rustc_hir::{def::DefKind, def_id::LocalDefId};
4+
use rustc_hir::{intravisit, CRATE_HIR_ID};
35
use rustc_middle::query::Providers;
46
use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
57
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -51,7 +53,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
5153

5254
fn parent(&self) -> Option<LocalDefId> {
5355
match self.tcx.def_kind(self.item) {
54-
DefKind::Fn => None,
56+
DefKind::AnonConst | DefKind::InlineConst | DefKind::Fn | DefKind::TyAlias => None,
5557
DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
5658
Some(self.tcx.local_parent(self.item))
5759
}
@@ -61,6 +63,73 @@ impl<'tcx> OpaqueTypeCollector<'tcx> {
6163
),
6264
}
6365
}
66+
67+
/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `self.item`.
68+
///
69+
/// Example:
70+
/// ```ignore UNSOLVED (is this a bug?)
71+
/// # #![feature(type_alias_impl_trait)]
72+
/// pub mod foo {
73+
/// pub mod bar {
74+
/// pub trait Bar { /* ... */ }
75+
/// pub type Baz = impl Bar;
76+
///
77+
/// # impl Bar for () {}
78+
/// fn f1() -> Baz { /* ... */ }
79+
/// }
80+
/// fn f2() -> bar::Baz { /* ... */ }
81+
/// }
82+
/// ```
83+
///
84+
/// and `opaque_def_id` is the `DefId` of the definition of the opaque type `Baz`.
85+
/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
86+
#[instrument(level = "trace", skip(self), ret)]
87+
fn check_tait_defining_scope(&self, opaque_def_id: LocalDefId) -> bool {
88+
let mut hir_id = self.tcx.hir().local_def_id_to_hir_id(self.item);
89+
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(opaque_def_id);
90+
91+
// Named opaque types can be defined by any siblings or children of siblings.
92+
let scope = self.tcx.hir().get_defining_scope(opaque_hir_id);
93+
// We walk up the node tree until we hit the root or the scope of the opaque type.
94+
while hir_id != scope && hir_id != CRATE_HIR_ID {
95+
hir_id = self.tcx.hir().get_parent_item(hir_id).into();
96+
}
97+
// Syntactically, we are allowed to define the concrete type if:
98+
hir_id == scope
99+
}
100+
101+
fn collect_body_and_predicate_taits(&mut self) {
102+
// Look at all where bounds.
103+
self.tcx.predicates_of(self.item).instantiate_identity(self.tcx).visit_with(self);
104+
// An item is allowed to constrain opaques declared within its own body (but not nested within
105+
// nested functions).
106+
self.collect_taits_declared_in_body();
107+
}
108+
109+
#[instrument(level = "trace", skip(self))]
110+
fn collect_taits_declared_in_body(&mut self) {
111+
let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(self.item)).value;
112+
struct TaitInBodyFinder<'a, 'tcx> {
113+
collector: &'a mut OpaqueTypeCollector<'tcx>,
114+
}
115+
impl<'v> intravisit::Visitor<'v> for TaitInBodyFinder<'_, '_> {
116+
#[instrument(level = "trace", skip(self))]
117+
fn visit_nested_item(&mut self, id: rustc_hir::ItemId) {
118+
let id = id.owner_id.def_id;
119+
if let DefKind::TyAlias = self.collector.tcx.def_kind(id) {
120+
let items = self.collector.tcx.opaque_types_defined_by(id);
121+
self.collector.opaques.extend(items);
122+
}
123+
}
124+
#[instrument(level = "trace", skip(self))]
125+
// Recurse into these, as they are type checked with their parent
126+
fn visit_nested_body(&mut self, id: rustc_hir::BodyId) {
127+
let body = self.collector.tcx.hir().body(id);
128+
self.visit_body(body);
129+
}
130+
}
131+
TaitInBodyFinder { collector: self }.visit_expr(body);
132+
}
64133
}
65134

66135
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
@@ -73,6 +142,21 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
73142
return ControlFlow::Continue(());
74143
}
75144

145+
// TAITs outside their defining scopes are ignored.
146+
let origin = self.tcx.opaque_type_origin(alias_ty.def_id.expect_local());
147+
trace!(?origin);
148+
match origin {
149+
rustc_hir::OpaqueTyOrigin::FnReturn(_)
150+
| rustc_hir::OpaqueTyOrigin::AsyncFn(_) => {}
151+
rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
152+
if !in_assoc_ty {
153+
if !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) {
154+
return ControlFlow::Continue(());
155+
}
156+
}
157+
}
158+
}
159+
76160
self.opaques.push(alias_ty.def_id.expect_local());
77161

78162
match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) {
@@ -188,65 +272,63 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
188272
fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] {
189273
let kind = tcx.def_kind(item);
190274
trace!(?kind);
191-
// FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types.
275+
let mut collector = OpaqueTypeCollector::new(tcx, item);
192276
match kind {
277+
// Walk over the signature of the function-like to find the opaques.
278+
DefKind::AssocFn | DefKind::Fn => {
279+
let ty_sig = tcx.fn_sig(item).subst_identity();
280+
let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap();
281+
// Walk over the inputs and outputs manually in order to get good spans for them.
282+
collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output());
283+
for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) {
284+
collector.visit_spanned(hir.span, ty.map_bound(|x| *x));
285+
}
286+
collector.collect_body_and_predicate_taits();
287+
}
288+
// Walk over the type of the item to find opaques.
289+
DefKind::Static(_) | DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
290+
let span = match tcx.hir().get_by_def_id(item).ty() {
291+
Some(ty) => ty.span,
292+
_ => tcx.def_span(item),
293+
};
294+
collector.visit_spanned(span, tcx.type_of(item).subst_identity());
295+
collector.collect_body_and_predicate_taits();
296+
}
193297
// We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
194-
DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
195-
let mut collector = OpaqueTypeCollector::new(tcx, item);
196-
match kind {
197-
// Walk over the signature of the function-like to find the opaques.
198-
DefKind::AssocFn | DefKind::Fn => {
199-
let ty_sig = tcx.fn_sig(item).subst_identity();
200-
let hir_sig = tcx.hir().get_by_def_id(item).fn_sig().unwrap();
201-
// Walk over the inputs and outputs manually in order to get good spans for them.
202-
collector.visit_spanned(hir_sig.decl.output.span(), ty_sig.output());
203-
for (hir, ty) in hir_sig.decl.inputs.iter().zip(ty_sig.inputs().iter()) {
204-
collector.visit_spanned(hir.span, ty.map_bound(|x| *x));
205-
}
206-
}
207-
// Walk over the type of the item to find opaques.
208-
DefKind::AssocTy | DefKind::AssocConst => {
209-
let span = match tcx.hir().get_by_def_id(item).ty() {
210-
Some(ty) => ty.span,
211-
_ => tcx.def_span(item),
212-
};
213-
collector.visit_spanned(span, tcx.type_of(item).subst_identity());
214-
}
215-
_ => unreachable!(),
298+
DefKind::TyAlias | DefKind::AssocTy => {
299+
tcx.type_of(item).subst_identity().visit_with(&mut collector);
300+
}
301+
DefKind::OpaqueTy => {
302+
for (pred, span) in tcx.explicit_item_bounds(item).subst_identity_iter_copied() {
303+
collector.visit_spanned(span, pred);
216304
}
217-
tcx.arena.alloc_from_iter(collector.opaques)
218305
}
219306
DefKind::Mod
220307
| DefKind::Struct
221308
| DefKind::Union
222309
| DefKind::Enum
223310
| DefKind::Variant
224311
| DefKind::Trait
225-
| DefKind::TyAlias
226312
| DefKind::ForeignTy
227313
| DefKind::TraitAlias
228314
| DefKind::TyParam
229-
| DefKind::Const
230315
| DefKind::ConstParam
231-
| DefKind::Static(_)
232316
| DefKind::Ctor(_, _)
233317
| DefKind::Macro(_)
234318
| DefKind::ExternCrate
235319
| DefKind::Use
236320
| DefKind::ForeignMod
237-
| DefKind::AnonConst
238-
| DefKind::InlineConst
239-
| DefKind::OpaqueTy
240321
| DefKind::ImplTraitPlaceholder
241322
| DefKind::Field
242323
| DefKind::LifetimeParam
243324
| DefKind::GlobalAsm
244-
| DefKind::Impl { .. }
245-
| DefKind::Closure
246-
| DefKind::Generator => {
247-
span_bug!(tcx.def_span(item), "{kind:?} is type checked as part of its parent")
325+
| DefKind::Impl { .. } => {}
326+
// Closures and generators are type checked with their parent, so there is no difference here.
327+
DefKind::Closure | DefKind::Generator | DefKind::InlineConst => {
328+
return tcx.opaque_types_defined_by(tcx.local_parent(item));
248329
}
249330
}
331+
tcx.arena.alloc_from_iter(collector.opaques)
250332
}
251333

252334
pub(super) fn provide(providers: &mut Providers) {

Diff for: tests/ui/feature-gates/feature-gate-type_alias_impl_trait.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn define() -> Bar {
1111

1212
type Foo2 = impl Debug;
1313

14-
fn define2() {
14+
fn define2(_: Foo2) {
1515
let x = || -> Foo2 { 42 };
1616
}
1717

@@ -20,13 +20,13 @@ type Foo3 = impl Debug;
2020
fn define3(x: Foo3) {
2121
let y: i32 = x;
2222
}
23-
fn define3_1() {
23+
fn define3_1(_: Foo3) {
2424
define3(42)
2525
}
2626

2727
type Foo4 = impl Debug;
2828

29-
fn define4() {
29+
fn define4(_: Foo4) {
3030
let y: Foo4 = 42;
3131
}
3232

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//! This test is reporting the wrong error. We need
2+
//! more inherent associated type tests that use opaque types
3+
//! in general. Some variant of this test should compile successfully.
4+
// known-bug: unknown
5+
// edition:2018
6+
7+
#![feature(impl_trait_in_assoc_type, inherent_associated_types)]
8+
#![allow(incomplete_features)]
9+
10+
use std::future::Future;
11+
12+
struct Foo<'a>(&'a mut ());
13+
14+
impl Foo<'_> {
15+
type Fut<'a> = impl Future<Output = ()>;
16+
//^ ERROR: the type `&mut ()` does not fulfill the required lifetime
17+
18+
fn make_fut<'a>(&'a self) -> Self::Fut<'a> {
19+
async { () }
20+
}
21+
}
22+
23+
fn main() {}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-90014-tait.rs:19:9
3+
|
4+
LL | type Fut<'a> = impl Future<Output = ()>;
5+
| ------------------------ the expected future
6+
...
7+
LL | fn make_fut<'a>(&'a self) -> Self::Fut<'a> {
8+
| ------------- expected `Foo<'_>::Fut<'a>` because of return type
9+
LL | async { () }
10+
| ^^^^^^^^^^^^ expected future, found `async` block
11+
|
12+
= note: expected opaque type `Foo<'_>::Fut<'a>`
13+
found `async` block `[async block@$DIR/issue-90014-tait.rs:19:9: 19:21]`
14+
note: this item must have the opaque type in its signature in order to be able to register hidden types
15+
--> $DIR/issue-90014-tait.rs:18:8
16+
|
17+
LL | fn make_fut<'a>(&'a self) -> Self::Fut<'a> {
18+
| ^^^^^^^^
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)