Skip to content

Commit d351515

Browse files
committed
Auto merge of #113636 - compiler-errors:opaque-recursive-check-bad, r=oli-obk
Restrict recursive opaque type check We have a recursive opaque check in writeback to avoid inferring the hidden of an opaque type to be itself: https://github.com/rust-lang/rust/blob/33a2c2487ac5d9927830ea4c1844335c6b9f77db/compiler/rustc_hir_typeck/src/writeback.rs#L556-L575 Issue #113619 treats `make_option2` as not defining the TAIT `TestImpl` since it is inferred to have the definition `TestImpl := B<TestImpl>`, which fails this check. This regressed in #102700 (5d15beb), I think due to the refactoring that made us record the hidden types of TAITs during writeback. However, nothing actually seems to go bad if we relax this recursion checker to only check for directly recursive definitions. This PR fixes #113619 by changing this recursive check from being a visitor to just checking that the hidden type is exactly the same as the opaque being inferred. Alternatively, we may be able to fix #113619 by restricting this recursion check only to RPITs/async fns. It seems to only be possible to use misuse the recursion check to cause ICEs for TAITs (though I didn't try too hard to create a bad RPIT example... may be possible, actually.) r? `@oli-obk` -- Fixes #113314
2 parents 42a982d + 6875589 commit d351515

File tree

5 files changed

+87
-20
lines changed

5 files changed

+87
-20
lines changed

compiler/rustc_hir_typeck/src/writeback.rs

+4-20
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,19 @@
33
// substitutions.
44

55
use crate::FnCtxt;
6-
use hir::def_id::LocalDefId;
76
use rustc_data_structures::unord::ExtendUnord;
87
use rustc_errors::{ErrorGuaranteed, StashKey};
98
use rustc_hir as hir;
109
use rustc_hir::intravisit::{self, Visitor};
1110
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
1211
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
1312
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
14-
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt};
13+
use rustc_middle::ty::visit::TypeVisitableExt;
1514
use rustc_middle::ty::{self, Ty, TyCtxt};
1615
use rustc_span::symbol::sym;
1716
use rustc_span::Span;
1817

1918
use std::mem;
20-
use std::ops::ControlFlow;
2119

2220
///////////////////////////////////////////////////////////////////////////
2321
// Entry point
@@ -565,23 +563,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
565563
let hidden_type = self.resolve(decl.hidden_type, &decl.hidden_type.span);
566564
let opaque_type_key = self.resolve(opaque_type_key, &decl.hidden_type.span);
567565

568-
struct RecursionChecker {
569-
def_id: LocalDefId,
570-
}
571-
impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for RecursionChecker {
572-
type BreakTy = ();
573-
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
574-
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *t.kind() {
575-
if def_id == self.def_id.to_def_id() {
576-
return ControlFlow::Break(());
577-
}
578-
}
579-
t.super_visit_with(self)
580-
}
581-
}
582-
if hidden_type
583-
.visit_with(&mut RecursionChecker { def_id: opaque_type_key.def_id })
584-
.is_break()
566+
if let ty::Alias(ty::Opaque, alias_ty) = hidden_type.ty.kind()
567+
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
568+
&& alias_ty.args == opaque_type_key.args
585569
{
586570
continue;
587571
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// issue: 113314
2+
3+
#![feature(type_alias_impl_trait)]
4+
5+
type Op = impl std::fmt::Display;
6+
fn foo() -> Op { &"hello world" }
7+
8+
fn transform<S>() -> impl std::fmt::Display {
9+
&0usize
10+
}
11+
fn bad() -> Op {
12+
transform::<Op>()
13+
//~^ ERROR concrete type differs from previous defining opaque type use
14+
}
15+
16+
fn main() {
17+
let mut x = foo();
18+
println!("{x}");
19+
x = bad();
20+
println!("{x}");
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: concrete type differs from previous defining opaque type use
2+
--> $DIR/recursive-tait-conflicting-defn-2.rs:12:5
3+
|
4+
LL | transform::<Op>()
5+
| ^^^^^^^^^^^^^^^^^ expected `&'static &'static str`, got `impl std::fmt::Display`
6+
|
7+
note: previous use here
8+
--> $DIR/recursive-tait-conflicting-defn-2.rs:6:18
9+
|
10+
LL | fn foo() -> Op { &"hello world" }
11+
| ^^^^^^^^^^^^^^
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// issue: 113596
2+
3+
#![feature(type_alias_impl_trait)]
4+
5+
trait Test {}
6+
7+
struct A;
8+
9+
impl Test for A {}
10+
11+
struct B<T> {
12+
inner: T,
13+
}
14+
15+
impl<T: Test> Test for B<T> {}
16+
17+
type TestImpl = impl Test;
18+
19+
fn test() -> TestImpl {
20+
A
21+
}
22+
23+
fn make_option() -> Option<TestImpl> {
24+
Some(test())
25+
}
26+
27+
fn make_option2() -> Option<TestImpl> {
28+
let inner = make_option().unwrap();
29+
30+
Some(B { inner })
31+
//~^ ERROR concrete type differs from previous defining opaque type use
32+
}
33+
34+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: concrete type differs from previous defining opaque type use
2+
--> $DIR/recursive-tait-conflicting-defn.rs:30:3
3+
|
4+
LL | Some(B { inner })
5+
| ^^^^^^^^^^^^^^^^^ expected `A`, got `B<TestImpl>`
6+
|
7+
note: previous use here
8+
--> $DIR/recursive-tait-conflicting-defn.rs:20:3
9+
|
10+
LL | A
11+
| ^
12+
13+
error: aborting due to previous error
14+

0 commit comments

Comments
 (0)