Prevent two opaque types in their defining scopes from being defined via the other
This commit is contained in:
parent
bae04fb3de
commit
7f608eb9ed
14 changed files with 216 additions and 56 deletions
|
@ -80,47 +80,69 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
if self.defining_use_anchor.is_some() {
|
if self.defining_use_anchor.is_some() {
|
||||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
||||||
ty::Opaque(def_id, substs) => Some(self.register_hidden_type(
|
ty::Opaque(def_id, substs) => {
|
||||||
OpaqueTypeKey { def_id, substs },
|
if let ty::Opaque(did2, _) = *b.kind() {
|
||||||
cause.clone(),
|
if self.opaque_type_origin(did2, cause.span).is_some() {
|
||||||
param_env,
|
self.tcx
|
||||||
b,
|
.sess
|
||||||
// Check that this is `impl Trait` type is
|
.struct_span_err(
|
||||||
// declared by `parent_def_id` -- i.e., one whose
|
cause.span,
|
||||||
// value we are inferring. At present, this is
|
"opaque type's hidden type cannot be another opaque type from the same scope",
|
||||||
// always true during the first phase of
|
)
|
||||||
// type-check, but not always true later on during
|
.span_label(cause.span, "one of the two opaque types used here has to be outside its defining scope")
|
||||||
// NLL. Once we support named opaque types more fully,
|
.span_note(
|
||||||
// this same scenario will be able to arise during all phases.
|
self.tcx.def_span(def_id),
|
||||||
//
|
"opaque type whose hidden type is being assigned",
|
||||||
// Here is an example using type alias `impl Trait`
|
)
|
||||||
// that indicates the distinction we are checking for:
|
.span_note(
|
||||||
//
|
self.tcx.def_span(did2),
|
||||||
// ```rust
|
"opaque type being used as hidden type",
|
||||||
// mod a {
|
)
|
||||||
// pub type Foo = impl Iterator;
|
.emit();
|
||||||
// pub fn make_foo() -> Foo { .. }
|
}
|
||||||
// }
|
}
|
||||||
//
|
Some(self.register_hidden_type(
|
||||||
// mod b {
|
OpaqueTypeKey { def_id, substs },
|
||||||
// fn foo() -> a::Foo { a::make_foo() }
|
cause.clone(),
|
||||||
// }
|
param_env,
|
||||||
// ```
|
b,
|
||||||
//
|
// Check that this is `impl Trait` type is
|
||||||
// Here, the return type of `foo` references an
|
// declared by `parent_def_id` -- i.e., one whose
|
||||||
// `Opaque` indeed, but not one whose value is
|
// value we are inferring. At present, this is
|
||||||
// presently being inferred. You can get into a
|
// always true during the first phase of
|
||||||
// similar situation with closure return types
|
// type-check, but not always true later on during
|
||||||
// today:
|
// NLL. Once we support named opaque types more fully,
|
||||||
//
|
// this same scenario will be able to arise during all phases.
|
||||||
// ```rust
|
//
|
||||||
// fn foo() -> impl Iterator { .. }
|
// Here is an example using type alias `impl Trait`
|
||||||
// fn bar() {
|
// that indicates the distinction we are checking for:
|
||||||
// let x = || foo(); // returns the Opaque assoc with `foo`
|
//
|
||||||
// }
|
// ```rust
|
||||||
// ```
|
// mod a {
|
||||||
self.opaque_type_origin(def_id, cause.span)?,
|
// pub type Foo = impl Iterator;
|
||||||
)),
|
// pub fn make_foo() -> Foo { .. }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// mod b {
|
||||||
|
// fn foo() -> a::Foo { a::make_foo() }
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Here, the return type of `foo` references an
|
||||||
|
// `Opaque` indeed, but not one whose value is
|
||||||
|
// presently being inferred. You can get into a
|
||||||
|
// similar situation with closure return types
|
||||||
|
// today:
|
||||||
|
//
|
||||||
|
// ```rust
|
||||||
|
// fn foo() -> impl Iterator { .. }
|
||||||
|
// fn bar() {
|
||||||
|
// let x = || foo(); // returns the Opaque assoc with `foo`
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
self.opaque_type_origin(def_id, cause.span)?,
|
||||||
|
))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(res) = process(a, b) {
|
if let Some(res) = process(a, b) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// run-pass
|
|
||||||
// ignore-compare-mode-chalk
|
// ignore-compare-mode-chalk
|
||||||
|
|
||||||
#![feature(fn_traits,
|
#![feature(fn_traits,
|
||||||
|
@ -590,7 +589,7 @@ fn test_format_month() {
|
||||||
fn format_months(it: impl Iterator<Item = impl DateIterator>)
|
fn format_months(it: impl Iterator<Item = impl DateIterator>)
|
||||||
-> impl Iterator<Item=impl Iterator<Item=String>>
|
-> impl Iterator<Item=impl Iterator<Item=String>>
|
||||||
{
|
{
|
||||||
it.map(format_month)
|
it.map(format_month) //~ ERROR opaque type's hidden type cannot be another opaque type
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes an iterator of iterators of strings; the sub-iterators are consumed
|
/// Takes an iterator of iterators of strings; the sub-iterators are consumed
|
||||||
|
|
19
src/test/ui/impl-trait/example-calendar.stderr
Normal file
19
src/test/ui/impl-trait/example-calendar.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error: opaque type's hidden type cannot be another opaque type from the same scope
|
||||||
|
--> $DIR/example-calendar.rs:592:5
|
||||||
|
|
|
||||||
|
LL | it.map(format_month)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
|
||||||
|
|
|
||||||
|
note: opaque type whose hidden type is being assigned
|
||||||
|
--> $DIR/example-calendar.rs:560:43
|
||||||
|
|
|
||||||
|
LL | fn format_month(it: impl DateIterator) -> impl Iterator<Item=String> {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: opaque type being used as hidden type
|
||||||
|
--> $DIR/example-calendar.rs:590:39
|
||||||
|
|
|
||||||
|
LL | -> impl Iterator<Item=impl Iterator<Item=String>>
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
// check-pass
|
|
||||||
|
|
||||||
type FooArg<'a> = &'a dyn ToString;
|
type FooArg<'a> = &'a dyn ToString;
|
||||||
type FooRet = impl std::fmt::Debug;
|
type FooRet = impl std::fmt::Debug;
|
||||||
|
|
||||||
|
@ -30,7 +28,7 @@ fn ham() -> Foo {
|
||||||
fn oof() -> impl std::fmt::Debug {
|
fn oof() -> impl std::fmt::Debug {
|
||||||
let mut bar = ham();
|
let mut bar = ham();
|
||||||
let func = bar.next().unwrap();
|
let func = bar.next().unwrap();
|
||||||
return func(&"oof");
|
return func(&"oof"); //~ ERROR opaque type's hidden type cannot be another opaque type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
19
src/test/ui/impl-trait/issues/issue-70877.stderr
Normal file
19
src/test/ui/impl-trait/issues/issue-70877.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error: opaque type's hidden type cannot be another opaque type from the same scope
|
||||||
|
--> $DIR/issue-70877.rs:31:12
|
||||||
|
|
|
||||||
|
LL | return func(&"oof");
|
||||||
|
| ^^^^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
|
||||||
|
|
|
||||||
|
note: opaque type whose hidden type is being assigned
|
||||||
|
--> $DIR/issue-70877.rs:28:13
|
||||||
|
|
|
||||||
|
LL | fn oof() -> impl std::fmt::Debug {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
note: opaque type being used as hidden type
|
||||||
|
--> $DIR/issue-70877.rs:4:15
|
||||||
|
|
|
||||||
|
LL | type FooRet = impl std::fmt::Debug;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
39
src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
Normal file
39
src/test/ui/impl-trait/issues/issue-88236-2.nll.stderr
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
error: higher-ranked subtype error
|
||||||
|
--> $DIR/issue-88236-2.rs:17:5
|
||||||
|
|
|
||||||
|
LL | &()
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: higher-ranked subtype error
|
||||||
|
--> $DIR/issue-88236-2.rs:17:5
|
||||||
|
|
|
||||||
|
LL | &()
|
||||||
|
| ^^^
|
||||||
|
|
||||||
|
error: lifetime may not live long enough
|
||||||
|
--> $DIR/issue-88236-2.rs:20:5
|
||||||
|
|
|
||||||
|
LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {
|
||||||
|
| -- lifetime `'b` defined here
|
||||||
|
LL | x
|
||||||
|
| ^ returning this value requires that `'b` must outlive `'static`
|
||||||
|
|
|
||||||
|
help: to allow this `impl Trait` to capture borrowed data with lifetime `'b`, add `'b` as a bound
|
||||||
|
|
|
||||||
|
LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b {
|
||||||
|
| ++++
|
||||||
|
|
||||||
|
error: higher-ranked subtype error
|
||||||
|
--> $DIR/issue-88236-2.rs:20:5
|
||||||
|
|
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: higher-ranked subtype error
|
||||||
|
--> $DIR/issue-88236-2.rs:20:5
|
||||||
|
|
|
||||||
|
LL | x
|
||||||
|
| ^
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
// check-pass
|
|
||||||
|
|
||||||
type A = impl Foo;
|
type A = impl Foo;
|
||||||
type B = impl Foo;
|
type B = impl Foo;
|
||||||
|
|
||||||
|
@ -12,6 +10,7 @@ fn muh(x: A) -> B {
|
||||||
return Bar; // B's hidden type is Bar
|
return Bar; // B's hidden type is Bar
|
||||||
}
|
}
|
||||||
x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
|
x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
|
||||||
|
//~^ ERROR opaque type's hidden type cannot be another opaque type
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Bar;
|
struct Bar;
|
||||||
|
|
19
src/test/ui/impl-trait/two_tait_defining_each_other.stderr
Normal file
19
src/test/ui/impl-trait/two_tait_defining_each_other.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error: opaque type's hidden type cannot be another opaque type from the same scope
|
||||||
|
--> $DIR/two_tait_defining_each_other.rs:12:5
|
||||||
|
|
|
||||||
|
LL | x // A's hidden type is `Bar`, because all the hidden types of `B` are compared with each other
|
||||||
|
| ^ one of the two opaque types used here has to be outside its defining scope
|
||||||
|
|
|
||||||
|
note: opaque type whose hidden type is being assigned
|
||||||
|
--> $DIR/two_tait_defining_each_other.rs:4:10
|
||||||
|
|
|
||||||
|
LL | type B = impl Foo;
|
||||||
|
| ^^^^^^^^
|
||||||
|
note: opaque type being used as hidden type
|
||||||
|
--> $DIR/two_tait_defining_each_other.rs:3:10
|
||||||
|
|
|
||||||
|
LL | type A = impl Foo;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
type A = impl Foo;
|
type A = impl Foo;
|
||||||
//~^ ERROR unconstrained opaque type
|
|
||||||
type B = impl Foo;
|
type B = impl Foo;
|
||||||
|
|
||||||
trait Foo {}
|
trait Foo {}
|
||||||
|
|
||||||
fn muh(x: A) -> B {
|
fn muh(x: A) -> B {
|
||||||
x // B's hidden type is A (opaquely)
|
x // B's hidden type is A (opaquely)
|
||||||
|
//~^ ERROR opaque type's hidden type cannot be another opaque type
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Bar;
|
struct Bar;
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
error: unconstrained opaque type
|
error: opaque type's hidden type cannot be another opaque type from the same scope
|
||||||
|
--> $DIR/two_tait_defining_each_other2.rs:9:5
|
||||||
|
|
|
||||||
|
LL | x // B's hidden type is A (opaquely)
|
||||||
|
| ^ one of the two opaque types used here has to be outside its defining scope
|
||||||
|
|
|
||||||
|
note: opaque type whose hidden type is being assigned
|
||||||
|
--> $DIR/two_tait_defining_each_other2.rs:4:10
|
||||||
|
|
|
||||||
|
LL | type B = impl Foo;
|
||||||
|
| ^^^^^^^^
|
||||||
|
note: opaque type being used as hidden type
|
||||||
--> $DIR/two_tait_defining_each_other2.rs:3:10
|
--> $DIR/two_tait_defining_each_other2.rs:3:10
|
||||||
|
|
|
|
||||||
LL | type A = impl Foo;
|
LL | type A = impl Foo;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
= note: `A` must be used in combination with a concrete type within the same module
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
// check-pass
|
|
||||||
|
|
||||||
type A = impl Foo;
|
type A = impl Foo;
|
||||||
type B = impl Foo;
|
type B = impl Foo;
|
||||||
|
|
||||||
|
@ -10,6 +8,7 @@ trait Foo {}
|
||||||
fn muh(x: A) -> B {
|
fn muh(x: A) -> B {
|
||||||
if false {
|
if false {
|
||||||
return x; // B's hidden type is A (opaquely)
|
return x; // B's hidden type is A (opaquely)
|
||||||
|
//~^ ERROR opaque type's hidden type cannot be another opaque type
|
||||||
}
|
}
|
||||||
Bar // A's hidden type is `Bar`, because all the return types are compared with each other
|
Bar // A's hidden type is `Bar`, because all the return types are compared with each other
|
||||||
}
|
}
|
||||||
|
|
19
src/test/ui/impl-trait/two_tait_defining_each_other3.stderr
Normal file
19
src/test/ui/impl-trait/two_tait_defining_each_other3.stderr
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
error: opaque type's hidden type cannot be another opaque type from the same scope
|
||||||
|
--> $DIR/two_tait_defining_each_other3.rs:10:16
|
||||||
|
|
|
||||||
|
LL | return x; // B's hidden type is A (opaquely)
|
||||||
|
| ^ one of the two opaque types used here has to be outside its defining scope
|
||||||
|
|
|
||||||
|
note: opaque type whose hidden type is being assigned
|
||||||
|
--> $DIR/two_tait_defining_each_other3.rs:4:10
|
||||||
|
|
|
||||||
|
LL | type B = impl Foo;
|
||||||
|
| ^^^^^^^^
|
||||||
|
note: opaque type being used as hidden type
|
||||||
|
--> $DIR/two_tait_defining_each_other3.rs:3:10
|
||||||
|
|
|
||||||
|
LL | type A = impl Foo;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
// build-pass (FIXME(62277): could be check-pass?)
|
|
||||||
mod my_mod {
|
mod my_mod {
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ mod my_mod {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_foot() -> Foot {
|
pub fn get_foot() -> Foot {
|
||||||
get_foo()
|
get_foo() //~ ERROR opaque type's hidden type cannot be another opaque type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
error: opaque type's hidden type cannot be another opaque type from the same scope
|
||||||
|
--> $DIR/nested_type_alias_impl_trait.rs:14:9
|
||||||
|
|
|
||||||
|
LL | get_foo()
|
||||||
|
| ^^^^^^^^^ one of the two opaque types used here has to be outside its defining scope
|
||||||
|
|
|
||||||
|
note: opaque type whose hidden type is being assigned
|
||||||
|
--> $DIR/nested_type_alias_impl_trait.rs:7:21
|
||||||
|
|
|
||||||
|
LL | pub type Foot = impl Debug;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
note: opaque type being used as hidden type
|
||||||
|
--> $DIR/nested_type_alias_impl_trait.rs:6:20
|
||||||
|
|
|
||||||
|
LL | pub type Foo = impl Debug;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue