Auto merge of #92007 - oli-obk:lazy_tait2, r=nikomatsakis

Lazy type-alias-impl-trait

Previously opaque types were processed by

1. replacing all mentions of them with inference variables
2. memorizing these inference variables in a side-table
3. at the end of typeck, resolve the inference variables in the side table and use the resolved type as the hidden type of the opaque type

This worked okayish for `impl Trait` in return position, but required lots of roundabout type inference hacks and processing.

This PR instead stops this process of replacing opaque types with inference variables, and just keeps the opaque types around.
Whenever an opaque type `O` is compared with another type `T`, we make the comparison succeed and record `T` as the hidden type. If `O` is compared to `U` while there is a recorded hidden type for it, we grab the recorded type (`T`) and compare that against `U`. This makes implementing

* https://github.com/rust-lang/rfcs/pull/2515

much simpler (previous attempts on the inference based scheme were very prone to ICEs and general misbehaviour that was not explainable except by random implementation defined oddities).

r? `@nikomatsakis`

fixes #93411
fixes #88236
This commit is contained in:
bors
2022-02-07 23:40:26 +00:00
359 changed files with 3311 additions and 2447 deletions

View File

@@ -53,17 +53,17 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
self.relate(a, b)
}
#[instrument(skip(self), level = "debug")]
fn regions(
&mut self,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
Ok(a)
}
#[instrument(skip(self), level = "debug")]
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b {
return Ok(a);
}

View File

@@ -30,6 +30,7 @@ use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@@ -464,9 +465,13 @@ pub struct TypeckResults<'tcx> {
/// this field will be set to `Some(ErrorReported)`.
pub tainted_by_errors: Option<ErrorReported>,
/// All the opaque types that are restricted to concrete types
/// by this function.
pub concrete_opaque_types: FxHashSet<DefId>,
/// All the opaque types that have hidden types set
/// by this function. For return-position-impl-trait we also store the
/// type here, so that mir-borrowck can figure out hidden types,
/// even if they are only set in dead code (which doesn't show up in MIR).
/// For type-alias-impl-trait, this map is only used to prevent query cycles,
/// so the hidden types are all `None`.
pub concrete_opaque_types: VecMap<DefId, Option<Ty<'tcx>>>,
/// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details.

View File

@@ -265,6 +265,10 @@ impl FlagComputation {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
self.add_ty(ty);
}
ty::PredicateKind::OpaqueType(opaque, ty) => {
self.add_ty(opaque);
self.add_ty(ty);
}
}
}

View File

@@ -1207,15 +1207,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
type BreakTy = FoundFlags;
#[inline]
#[instrument(level = "trace")]
fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
debug!(
"HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
t,
t.flags(),
self.flags
);
if t.flags().intersects(self.flags) {
#[instrument(skip(self), level = "trace")]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = t.flags();
trace!(t.flags=?t.flags());
if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
ControlFlow::CONTINUE
@@ -1235,7 +1231,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
}
#[inline]
#[instrument(level = "trace")]
#[instrument(skip(self), level = "trace")]
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_const(c);
trace!(r.flags=?flags);

View File

@@ -627,6 +627,11 @@ pub enum PredicateKind<'tcx> {
///
/// Only used for Chalk.
TypeWellFormedFromEnv(Ty<'tcx>),
/// Represents a hidden type assignment for an opaque type.
/// Such obligations get processed by checking whether the item currently being
/// type-checked may acually define it.
OpaqueType(Ty<'tcx>, Ty<'tcx>),
}
/// The crate outlives map is computed during typeck and contains the
@@ -986,6 +991,7 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::TypeOutlives(..)
| PredicateKind::ConstEvaluatable(..)
| PredicateKind::ConstEquate(..)
| PredicateKind::OpaqueType(..)
| PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
@@ -1004,6 +1010,7 @@ impl<'tcx> Predicate<'tcx> {
| PredicateKind::ClosureKind(..)
| PredicateKind::ConstEvaluatable(..)
| PredicateKind::ConstEquate(..)
| PredicateKind::OpaqueType(..)
| PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
@@ -1044,7 +1051,18 @@ impl<'tcx> InstantiatedPredicates<'tcx> {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, TypeFoldable)]
#[derive(
Copy,
Clone,
Debug,
PartialEq,
Eq,
HashStable,
TyEncodable,
TyDecodable,
TypeFoldable,
Lift
)]
pub struct OpaqueTypeKey<'tcx> {
pub def_id: DefId,
pub substs: SubstsRef<'tcx>,

View File

@@ -644,20 +644,23 @@ pub trait PrettyPrinter<'tcx>:
return Ok(self);
}
return with_no_queries(|| {
let def_key = self.tcx().def_key(def_id);
if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
p!(write("{}", name));
// FIXME(eddyb) print this with `print_def_path`.
if !substs.is_empty() {
p!("::");
p!(generic_delimiters(|cx| cx.comma_sep(substs.iter())));
let parent = self.tcx().parent(def_id).expect("opaque types always have a parent");
match self.tcx().def_kind(parent) {
DefKind::TyAlias | DefKind::AssocTy => {
if let ty::Opaque(d, _) = *self.tcx().type_of(parent).kind() {
if d == def_id {
// If the type alias directly starts with the `impl` of the
// opaque type we're printing, then skip the `::{opaque#1}`.
p!(print_def_path(parent, substs));
return Ok(self);
}
}
// Complex opaque type, e.g. `type Foo = (i32, impl Debug);`
p!(print_def_path(def_id, substs));
return Ok(self);
}
self.pretty_print_opaque_impl_type(def_id, substs)
});
_ => return self.pretty_print_opaque_impl_type(def_id, substs),
}
}
ty::Str => p!("str"),
ty::Generator(did, substs, movability) => {
@@ -2607,6 +2610,9 @@ define_print_and_forward_display! {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
p!("the type `", print(ty), "` is found in the environment")
}
ty::PredicateKind::OpaqueType(a, b) => {
p!("opaque type assigment with `", print(a), "` == `", print(b) ,"`")
}
}
}

View File

@@ -191,6 +191,9 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
write!(f, "TypeWellFormedFromEnv({:?})", ty)
}
ty::PredicateKind::OpaqueType(a, b) => {
write!(f, "OpaqueType({:?}, {:?})", a.kind(), b.kind())
}
}
}
}
@@ -463,6 +466,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
}
ty::PredicateKind::OpaqueType(opaque, ty) => {
Some(ty::PredicateKind::OpaqueType(tcx.lift(opaque)?, tcx.lift(ty)?))
}
}
}
}

View File

@@ -152,6 +152,7 @@ pub enum TyKind<'tcx> {
/// The anonymous type of a closure. Used to represent the type of
/// `|a| a`.
/// For the order of the substs see the `ClosureSubsts` type's documentation.
Closure(DefId, SubstsRef<'tcx>),
/// The anonymous type of a generator. Used to represent the type of
@@ -1815,6 +1816,13 @@ impl<'tcx> TyS<'tcx> {
}
}
pub fn expect_opaque_type(&self) -> ty::OpaqueTypeKey<'tcx> {
match *self.kind() {
Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs },
_ => bug!("`expect_opaque_type` called on non-opaque type: {}", self),
}
}
pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
match self.kind() {
Adt(def, substs) => {