Skip to content

Commit

Permalink
Make mir borrowck's use of opaque types independent of the typeck que…
Browse files Browse the repository at this point in the history
…ry's result
  • Loading branch information
oli-obk committed Jul 22, 2021
1 parent d693a98 commit 6d76002
Show file tree
Hide file tree
Showing 20 changed files with 162 additions and 261 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_data_structures/src/vec_map.rs
Expand Up @@ -70,6 +70,10 @@ where
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
self.into_iter()
}

pub fn retain(&mut self, f: impl Fn(&(K, V)) -> bool) {
self.0.retain(f)
}
}

impl<K, V> Default for VecMap<K, V> {
Expand Down
149 changes: 62 additions & 87 deletions compiler/rustc_mir/src/borrow_check/type_check/mod.rs
Expand Up @@ -26,7 +26,7 @@ use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef, UserSubsts};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::{
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
Expand Down Expand Up @@ -60,7 +60,6 @@ use crate::borrow_check::{
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
},
region_infer::{ClosureRegionRequirementsExt, TypeTest},
renumber,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions},
Upvar,
Expand Down Expand Up @@ -180,7 +179,66 @@ pub(crate) fn type_check<'mir, 'tcx>(
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);

translate_outlives_facts(&mut cx);
cx.opaque_type_values
let mut opaque_type_values = cx.opaque_type_values;

for (_, revealed_ty) in &mut opaque_type_values {
// FIXME(oli-obk): Instead of looping, implement a visitor like
// FullTypeResolver. We can't use FullTypeResolver here, as that will
// resolve lifetimes lexically, which it can't because we didn't do old
// borrowck stuff. We want to use MIR borrowck information instead.

while revealed_ty.has_infer_types_or_consts() {
let prev = *revealed_ty;
trace!(prev=?prev.kind());
let type_resolved = infcx.shallow_resolve(prev);
trace!(type_resolved=?type_resolved.kind());
if prev == type_resolved {
infcx.tcx.sess.delay_span_bug(
body.span,
&format!("could not resolve {:#?}", type_resolved.kind()),
);
*revealed_ty = infcx.tcx.ty_error();
break;
}
*revealed_ty = type_resolved;
}
}

opaque_type_values.retain(|(opaque_type_key, resolved_ty)| {
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
*def_id == opaque_type_key.def_id
} else {
false
};

if concrete_is_opaque {
// We're using an opaque `impl Trait` type without
// 'revealing' it. For example, code like this:
//
// type Foo = impl Debug;
// fn foo1() -> Foo { ... }
// fn foo2() -> Foo { foo1() }
//
// In `foo2`, we're not revealing the type of `Foo` - we're
// just treating it as the opaque type.
//
// When this occurs, we do *not* want to try to equate
// the concrete type with the underlying defining type
// of the opaque type - this will always fail, since
// the defining type of an opaque type is always
// some other type (e.g. not itself)
// Essentially, none of the normal obligations apply here -
// we're just passing around some unknown opaque type,
// without actually looking at the underlying type it
// gets 'revealed' into
debug!(
"eq_opaque_type_and_type: non-defining use of {:?}",
opaque_type_key.def_id,
);
}
!concrete_is_opaque
});
opaque_type_values
},
);

Expand Down Expand Up @@ -1240,13 +1298,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}

let infcx = self.infcx;
let tcx = infcx.tcx;
let param_env = self.param_env;
let body = self.body;
let mir_def_id = body.source.def_id().expect_local();

// the "concrete opaque types" maps
let concrete_opaque_types = &tcx.typeck(mir_def_id).concrete_opaque_types;
let mut opaque_type_values = VecMap::new();

debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id);
Expand Down Expand Up @@ -1296,88 +1351,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
.eq(output_ty, revealed_ty)?,
);

// For each opaque type `Foo<T>` inferred by this value, we want to equate
// the inference variable `?T` with the revealed type that was computed
// earlier by type check.
for &(opaque_type_key, opaque_decl) in &opaque_type_map {
let resolved_ty = infcx.resolve_vars_if_possible(opaque_decl.concrete_ty);
let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
*def_id == opaque_type_key.def_id
} else {
false
};

// The revealed type computed by the earlier phase of type check.
// In our example, this would be `(U, u32)`. Note that this references
// the type parameter `U` from the definition of `Foo`.
let concrete_ty = match concrete_opaque_types
.get_by(|(key, _)| key.def_id == opaque_type_key.def_id)
{
None => {
if !concrete_is_opaque {
tcx.sess.delay_span_bug(
body.span,
&format!(
"Non-defining use of {:?} with revealed type",
opaque_type_key.def_id,
),
);
}
continue;
}
Some(concrete_ty) => concrete_ty,
};
debug!("concrete_ty = {:?}", concrete_ty);

// Apply the substitution, in this case `[U -> T]`, so that the
// concrete type becomes `Foo<(T, u32)>`
let subst_opaque_defn_ty = concrete_ty.subst(tcx, opaque_type_key.substs);

// "Renumber" this, meaning that we replace all the regions
// with fresh inference variables. Not relevant to our example.
let renumbered_opaque_defn_ty =
renumber::renumber_regions(infcx, subst_opaque_defn_ty);

debug!(
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
);

if !concrete_is_opaque {
// Equate the instantiated opaque type `opaque_decl.concrete_ty` (`?T`,
// in our example) with the renumbered version that we took from
// the type check results (`Foo<(T, u32)>`).
obligations.add(
infcx
.at(&ObligationCause::dummy(), param_env)
.eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
);
opaque_type_values.insert(opaque_type_key, renumbered_opaque_defn_ty);
} else {
// We're using an opaque `impl Trait` type without
// 'revealing' it. For example, code like this:
//
// type Foo = impl Debug;
// fn foo1() -> Foo { ... }
// fn foo2() -> Foo { foo1() }
//
// In `foo2`, we're not revealing the type of `Foo` - we're
// just treating it as the opaque type.
//
// When this occurs, we do *not* want to try to equate
// the concrete type with the underlying defining type
// of the opaque type - this will always fail, since
// the defining type of an opaque type is always
// some other type (e.g. not itself)
// Essentially, none of the normal obligations apply here -
// we're just passing around some unknown opaque type,
// without actually looking at the underlying type it
// gets 'revealed' into
debug!(
"eq_opaque_type_and_type: non-defining use of {:?}",
opaque_type_key.def_id,
);
}
opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty);
}

debug!("eq_opaque_type_and_type: equated");
Expand Down
Expand Up @@ -29,7 +29,6 @@ impl Bar for AssocNoCopy {
impl Thing for AssocNoCopy {
type Out = Box<dyn Bar<Assoc: Copy>>;
//~^ ERROR the trait bound `String: Copy` is not satisfied
//~| ERROR the trait bound `String: Copy` is not satisfied

fn func() -> Self::Out {
Box::new(AssocNoCopy)
Expand Down
Expand Up @@ -4,12 +4,6 @@ error[E0277]: the trait bound `String: Copy` is not satisfied
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`

error[E0277]: the trait bound `String: Copy` is not satisfied
--> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:30:28
|
LL | type Out = Box<dyn Bar<Assoc: Copy>>;
| ^^^^^^^^^^^ the trait `Copy` is not implemented for `String`

error: aborting due to 2 previous errors
error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
1 change: 0 additions & 1 deletion src/test/ui/impl-trait/auto-trait-leak.rs
Expand Up @@ -12,7 +12,6 @@ fn main() {
fn cycle1() -> impl Clone {
//~^ ERROR cycle detected
send(cycle2().clone());
//~^ ERROR cannot be sent between threads safely

Rc::new(Cell::new(5))
}
Expand Down
34 changes: 9 additions & 25 deletions src/test/ui/impl-trait/auto-trait-leak.stderr
Expand Up @@ -36,37 +36,37 @@ LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
note: ...which requires computing type of `cycle2::{opaque#0}`...
--> $DIR/auto-trait-leak.rs:20:16
--> $DIR/auto-trait-leak.rs:19:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:20:1
--> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:20:1
--> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:20:1
--> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:20:1
--> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `cycle2`...
--> $DIR/auto-trait-leak.rs:20:1
--> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:20:1
--> $DIR/auto-trait-leak.rs:19:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -84,22 +84,6 @@ LL | | Rc::new(String::from("foo"))
LL | | }
| |_^

error[E0277]: `Rc<String>` cannot be sent between threads safely
--> $DIR/auto-trait-leak.rs:14:5
|
LL | fn send<T: Send>(_: T) {}
| ---- required by this bound in `send`
...
LL | send(cycle2().clone());
| ^^^^ `Rc<String>` cannot be sent between threads safely
...
LL | fn cycle2() -> impl Clone {
| ---------- within this `impl Clone`
|
= help: within `impl Clone`, the trait `Send` is not implemented for `Rc<String>`
= note: required because it appears within the type `impl Clone`

error: aborting due to 2 previous errors
error: aborting due to previous error

Some errors have detailed explanations: E0277, E0391.
For more information about an error, try `rustc --explain E0277`.
For more information about this error, try `rustc --explain E0391`.
Expand Up @@ -36,16 +36,7 @@ LL | type WrongGeneric<T> = impl 'static;
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/generic_type_does_not_live_long_enough.rs:12:24
|
LL | type WrongGeneric<T> = impl 'static;
| ^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
= note: ...so that the type `T` will meet its required lifetime bounds

error: aborting due to 4 previous errors; 1 warning emitted
error: aborting due to 3 previous errors; 1 warning emitted

Some errors have detailed explanations: E0308, E0310.
For more information about an error, try `rustc --explain E0308`.
Expand Up @@ -27,16 +27,7 @@ LL | type WrongGeneric<T> = impl 'static;
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
| - help: consider adding an explicit lifetime bound...: `T: 'static`

error[E0310]: the parameter type `T` may not live long enough
--> $DIR/generic_type_does_not_live_long_enough.rs:12:24
|
LL | type WrongGeneric<T> = impl 'static;
| ^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `T: 'static`...
= note: ...so that the type `T` will meet its required lifetime bounds

error: aborting due to 4 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0308, E0310.
For more information about an error, try `rustc --explain E0308`.
Expand Up @@ -11,7 +11,6 @@ fn main() {

type WrongGeneric<T> = impl 'static;
//~^ ERROR the parameter type `T` may not live long enough
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR: at least one trait must be specified

fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
Expand Down
Expand Up @@ -16,52 +16,5 @@ LL | type Bar = impl Baz<Self, Self>;
= note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`

error[E0308]: mismatched types
--> $DIR/issue-57611-trait-alias.rs:20:16
|
LL | type Bar = impl Baz<Self, Self>;
| ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `for<'r> Fn<(&'r X,)>`
found type `Fn<(&'<empty> X,)>`
note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-57611-trait-alias.rs:28:9
|
LL | |x| x
| ^^^^^

error: implementation of `FnOnce` is not general enough
--> $DIR/issue-57611-trait-alias.rs:20:16
|
LL | type Bar = impl Baz<Self, Self>;
| ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`

error[E0308]: mismatched types
--> $DIR/issue-57611-trait-alias.rs:20:16
|
LL | type Bar = impl Baz<Self, Self>;
| ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
|
= note: expected type `for<'r> Fn<(&'r X,)>`
found type `Fn<(&'<empty> X,)>`
note: this closure does not fulfill the lifetime requirements
--> $DIR/issue-57611-trait-alias.rs:28:9
|
LL | |x| x
| ^^^^^

error: implementation of `FnOnce` is not general enough
--> $DIR/issue-57611-trait-alias.rs:20:16
|
LL | type Bar = impl Baz<Self, Self>;
| ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 X) -> &'2 X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`

error: aborting due to 5 previous errors; 1 warning emitted
error: aborting due to previous error; 1 warning emitted

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 6d76002

Please sign in to comment.