Skip to content

Commit 7f608eb

Browse files
committed
Prevent two opaque types in their defining scopes from being defined via the other
1 parent bae04fb commit 7f608eb

14 files changed

+216
-56
lines changed

compiler/rustc_infer/src/infer/opaque_types.rs

Lines changed: 63 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -80,47 +80,69 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
8080
}
8181
if self.defining_use_anchor.is_some() {
8282
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
83-
ty::Opaque(def_id, substs) => Some(self.register_hidden_type(
84-
OpaqueTypeKey { def_id, substs },
85-
cause.clone(),
86-
param_env,
87-
b,
88-
// Check that this is `impl Trait` type is
89-
// declared by `parent_def_id` -- i.e., one whose
90-
// value we are inferring. At present, this is
91-
// always true during the first phase of
92-
// type-check, but not always true later on during
93-
// NLL. Once we support named opaque types more fully,
94-
// this same scenario will be able to arise during all phases.
95-
//
96-
// Here is an example using type alias `impl Trait`
97-
// that indicates the distinction we are checking for:
98-
//
99-
// ```rust
100-
// mod a {
101-
// pub type Foo = impl Iterator;
102-
// pub fn make_foo() -> Foo { .. }
103-
// }
104-
//
105-
// mod b {
106-
// fn foo() -> a::Foo { a::make_foo() }
107-
// }
108-
// ```
109-
//
110-
// Here, the return type of `foo` references an
111-
// `Opaque` indeed, but not one whose value is
112-
// presently being inferred. You can get into a
113-
// similar situation with closure return types
114-
// today:
115-
//
116-
// ```rust
117-
// fn foo() -> impl Iterator { .. }
118-
// fn bar() {
119-
// let x = || foo(); // returns the Opaque assoc with `foo`
120-
// }
121-
// ```
122-
self.opaque_type_origin(def_id, cause.span)?,
123-
)),
83+
ty::Opaque(def_id, substs) => {
84+
if let ty::Opaque(did2, _) = *b.kind() {
85+
if self.opaque_type_origin(did2, cause.span).is_some() {
86+
self.tcx
87+
.sess
88+
.struct_span_err(
89+
cause.span,
90+
"opaque type's hidden type cannot be another opaque type from the same scope",
91+
)
92+
.span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
93+
.span_note(
94+
self.tcx.def_span(def_id),
95+
"opaque type whose hidden type is being assigned",
96+
)
97+
.span_note(
98+
self.tcx.def_span(did2),
99+
"opaque type being used as hidden type",
100+
)
101+
.emit();
102+
}
103+
}
104+
Some(self.register_hidden_type(
105+
OpaqueTypeKey { def_id, substs },
106+
cause.clone(),
107+
param_env,
108+
b,
109+
// Check that this is `impl Trait` type is
110+
// declared by `parent_def_id` -- i.e., one whose
111+
// value we are inferring. At present, this is
112+
// always true during the first phase of
113+
// type-check, but not always true later on during
114+
// NLL. Once we support named opaque types more fully,
115+
// this same scenario will be able to arise during all phases.
116+
//
117+
// Here is an example using type alias `impl Trait`
118+
// that indicates the distinction we are checking for:
119+
//
120+
// ```rust
121+
// mod a {
122+
// pub type Foo = impl Iterator;
123+
// pub fn make_foo() -> Foo { .. }
124+
// }
125+
//
126+
// mod b {
127+
// fn foo() -> a::Foo { a::make_foo() }
128+
// }
129+
// ```
130+
//
131+
// Here, the return type of `foo` references an
132+
// `Opaque` indeed, but not one whose value is
133+
// presently being inferred. You can get into a
134+
// similar situation with closure return types
135+
// today:
136+
//
137+
// ```rust
138+
// fn foo() -> impl Iterator { .. }
139+
// fn bar() {
140+
// let x = || foo(); // returns the Opaque assoc with `foo`
141+
// }
142+
// ```
143+
self.opaque_type_origin(def_id, cause.span)?,
144+
))
145+
}
124146
_ => None,
125147
};
126148
if let Some(res) = process(a, b) {

src/test/ui/impl-trait/example-calendar.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// run-pass
21
// ignore-compare-mode-chalk
32

43
#![feature(fn_traits,
@@ -590,7 +589,7 @@ fn test_format_month() {
590589
fn format_months(it: impl Iterator<Item = impl DateIterator>)
591590
-> impl Iterator<Item=impl Iterator<Item=String>>
592591
{
593-
it.map(format_month)
592+
it.map(format_month) //~ ERROR opaque type's hidden type cannot be another opaque type
594593
}
595594

596595
/// Takes an iterator of iterators of strings; the sub-iterators are consumed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: opaque type's hidden type cannot be another opaque type from the same scope
2+
--> $DIR/example-calendar.rs:592:5
3+
|
4+
LL | it.map(format_month)
5+
| ^^^^^^^^^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
6+
|
7+
note: opaque type whose hidden type is being assigned
8+
--> $DIR/example-calendar.rs:560:43
9+
|
10+
LL | fn format_month(it: impl DateIterator) -> impl Iterator<Item=String> {
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
note: opaque type being used as hidden type
13+
--> $DIR/example-calendar.rs:590:39
14+
|
15+
LL | -> impl Iterator<Item=impl Iterator<Item=String>>
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+

src/test/ui/impl-trait/issues/issue-70877.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#![feature(type_alias_impl_trait)]
22

3-
// check-pass
4-
53
type FooArg<'a> = &'a dyn ToString;
64
type FooRet = impl std::fmt::Debug;
75

@@ -30,7 +28,7 @@ fn ham() -> Foo {
3028
fn oof() -> impl std::fmt::Debug {
3129
let mut bar = ham();
3230
let func = bar.next().unwrap();
33-
return func(&"oof");
31+
return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type
3432
}
3533

3634
fn main() {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: opaque type's hidden type cannot be another opaque type from the same scope
2+
--> $DIR/issue-70877.rs:31:12
3+
|
4+
LL | return func(&"oof");
5+
| ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
6+
|
7+
note: opaque type whose hidden type is being assigned
8+
--> $DIR/issue-70877.rs:28:13
9+
|
10+
LL | fn oof() -> impl std::fmt::Debug {
11+
| ^^^^^^^^^^^^^^^^^^^^
12+
note: opaque type being used as hidden type
13+
--> $DIR/issue-70877.rs:4:15
14+
|
15+
LL | type FooRet = impl std::fmt::Debug;
16+
| ^^^^^^^^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error: higher-ranked subtype error
2+
--> $DIR/issue-88236-2.rs:17:5
3+
|
4+
LL | &()
5+
| ^^^
6+
7+
error: higher-ranked subtype error
8+
--> $DIR/issue-88236-2.rs:17:5
9+
|
10+
LL | &()
11+
| ^^^
12+
13+
error: lifetime may not live long enough
14+
--> $DIR/issue-88236-2.rs:20:5
15+
|
16+
LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
17+
| -- lifetime `'b` defined here
18+
LL | x
19+
| ^ returning this value requires that `'b` must outlive `'static`
20+
|
21+
help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
22+
|
23+
LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
24+
| ++++
25+
26+
error: higher-ranked subtype error
27+
--> $DIR/issue-88236-2.rs:20:5
28+
|
29+
LL | x
30+
| ^
31+
32+
error: higher-ranked subtype error
33+
--> $DIR/issue-88236-2.rs:20:5
34+
|
35+
LL | x
36+
| ^
37+
38+
error: aborting due to 5 previous errors
39+

src/test/ui/impl-trait/two_tait_defining_each_other.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#![feature(type_alias_impl_trait)]
22

3-
// check-pass
4-
53
type A = impl Foo;
64
type B = impl Foo;
75

@@ -12,6 +10,7 @@ fn muh(x: A) -> B {
1210
return Bar; // B's hidden type is Bar
1311
}
1412
x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
13+
//~^ ERROR opaque type's hidden type cannot be another opaque type
1514
}
1615

1716
struct Bar;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: opaque type's hidden type cannot be another opaque type from the same scope
2+
--> $DIR/two_tait_defining_each_other.rs:12:5
3+
|
4+
LL | x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
5+
| ^ one of the two opaque types used here has to be outside its defining scope
6+
|
7+
note: opaque type whose hidden type is being assigned
8+
--> $DIR/two_tait_defining_each_other.rs:4:10
9+
|
10+
LL | type B = impl Foo;
11+
| ^^^^^^^^
12+
note: opaque type being used as hidden type
13+
--> $DIR/two_tait_defining_each_other.rs:3:10
14+
|
15+
LL | type A = impl Foo;
16+
| ^^^^^^^^
17+
18+
error: aborting due to previous error
19+

src/test/ui/impl-trait/two_tait_defining_each_other2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#![feature(type_alias_impl_trait)]
22

33
type A = impl Foo;
4-
//~^ ERROR unconstrained opaque type
54
type B = impl Foo;
65

76
trait Foo {}
87

98
fn muh(x: A) -> B {
109
x // B's hidden type is A (opaquely)
10+
//~^ ERROR opaque type's hidden type cannot be another opaque type
1111
}
1212

1313
struct Bar;
Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
error: unconstrained opaque type
1+
error: opaque type's hidden type cannot be another opaque type from the same scope
2+
--> $DIR/two_tait_defining_each_other2.rs:9:5
3+
|
4+
LL | x // B's hidden type is A (opaquely)
5+
| ^ one of the two opaque types used here has to be outside its defining scope
6+
|
7+
note: opaque type whose hidden type is being assigned
8+
--> $DIR/two_tait_defining_each_other2.rs:4:10
9+
|
10+
LL | type B = impl Foo;
11+
| ^^^^^^^^
12+
note: opaque type being used as hidden type
213
--> $DIR/two_tait_defining_each_other2.rs:3:10
314
|
415
LL | type A = impl Foo;
516
| ^^^^^^^^
6-
|
7-
= note: `A` must be used in combination with a concrete type within the same module
817

918
error: aborting due to previous error
1019

src/test/ui/impl-trait/two_tait_defining_each_other3.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#![feature(type_alias_impl_trait)]
22

3-
// check-pass
4-
53
type A = impl Foo;
64
type B = impl Foo;
75

@@ -10,6 +8,7 @@ trait Foo {}
108
fn muh(x: A) -> B {
119
if false {
1210
return x; // B's hidden type is A (opaquely)
11+
//~^ ERROR opaque type's hidden type cannot be another opaque type
1312
}
1413
Bar // A's hidden type is `Bar`, because all the return types are compared with each other
1514
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: opaque type's hidden type cannot be another opaque type from the same scope
2+
--> $DIR/two_tait_defining_each_other3.rs:10:16
3+
|
4+
LL | return x; // B's hidden type is A (opaquely)
5+
| ^ one of the two opaque types used here has to be outside its defining scope
6+
|
7+
note: opaque type whose hidden type is being assigned
8+
--> $DIR/two_tait_defining_each_other3.rs:4:10
9+
|
10+
LL | type B = impl Foo;
11+
| ^^^^^^^^
12+
note: opaque type being used as hidden type
13+
--> $DIR/two_tait_defining_each_other3.rs:3:10
14+
|
15+
LL | type A = impl Foo;
16+
| ^^^^^^^^
17+
18+
error: aborting due to previous error
19+

src/test/ui/type-alias-impl-trait/nested_type_alias_impl_trait.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![feature(type_alias_impl_trait)]
2-
// build-pass (FIXME(62277): could be check-pass?)
2+
33
mod my_mod {
44
use std::fmt::Debug;
55

@@ -11,7 +11,7 @@ mod my_mod {
1111
}
1212

1313
pub fn get_foot() -> Foot {
14-
get_foo()
14+
get_foo() //~ ERROR opaque type's hidden type cannot be another opaque type
1515
}
1616
}
1717

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error: opaque type's hidden type cannot be another opaque type from the same scope
2+
--> $DIR/nested_type_alias_impl_trait.rs:14:9
3+
|
4+
LL | get_foo()
5+
| ^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
6+
|
7+
note: opaque type whose hidden type is being assigned
8+
--> $DIR/nested_type_alias_impl_trait.rs:7:21
9+
|
10+
LL | pub type Foot = impl Debug;
11+
| ^^^^^^^^^^
12+
note: opaque type being used as hidden type
13+
--> $DIR/nested_type_alias_impl_trait.rs:6:20
14+
|
15+
LL | pub type Foo = impl Debug;
16+
| ^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+

0 commit comments

Comments
 (0)