take opaq types

This commit is contained in:
ouz-a 2022-07-02 16:37:49 +03:00
parent 03d488b48a
commit 7c0fb38095
18 changed files with 293 additions and 185 deletions

View file

@ -239,17 +239,31 @@ impl<'tcx> InferCtxtInner<'tcx> {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DefiningAnchor {
/// `DefId` of the item.
Bind(LocalDefId),
/// When opaque types are not resolved, we `Bubble` up, meaning
/// return the opaque/hidden type pair from query, for caller of query to handle it.
Bubble,
/// Used to catch type mismatch errors when handling opaque types.
Error,
}
pub struct InferCtxt<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
/// The `DefId` of the item in whose context we are performing inference or typeck.
/// It is used to check whether an opaque type use is a defining use.
///
/// If it is `None`, we can't resolve opaque types here and need to bubble up
/// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up
/// the obligation. This frequently happens for
/// short lived InferCtxt within queries. The opaque type obligations are forwarded
/// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
pub defining_use_anchor: Option<LocalDefId>,
///
/// It is default value is `DefiningAnchor::Error`, this way it is easier to catch errors that
/// might come up during inference or typeck.
pub defining_use_anchor: DefiningAnchor,
/// During type-checking/inference of a body, `in_progress_typeck_results`
/// contains a reference to the typeck results being built up, which are
@ -526,7 +540,7 @@ impl<'tcx> fmt::Display for FixupError<'tcx> {
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
defining_use_anchor: Option<LocalDefId>,
defining_use_anchor: DefiningAnchor,
}
pub trait TyCtxtInferExt<'tcx> {
@ -535,7 +549,11 @@ pub trait TyCtxtInferExt<'tcx> {
impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
InferCtxtBuilder {
tcx: self,
defining_use_anchor: DefiningAnchor::Error,
fresh_typeck_results: None,
}
}
}
@ -545,7 +563,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// Will also change the scope for opaque type defining use checks to the given owner.
pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
self.with_opaque_type_inference(table_owner)
self.with_opaque_type_inference(DefiningAnchor::Bind(table_owner))
}
/// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
@ -554,8 +572,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
/// It is only meant to be called in two places, for typeck
/// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
/// in mir borrowck.
pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
self.defining_use_anchor = Some(defining_use_anchor);
pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor) -> Self {
self.defining_use_anchor = defining_use_anchor;
self
}

View file

@ -1,4 +1,4 @@
use crate::infer::{InferCtxt, InferOk};
use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
use crate::traits;
use hir::def_id::{DefId, LocalDefId};
use hir::{HirId, OpaqueTyOrigin};
@ -101,44 +101,46 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
ty::Opaque(def_id, substs) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = if self.defining_use_anchor.is_some() {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
// always true during the first phase of
// type-check, but not always true later on during
// NLL. Once we support named opaque types more fully,
// this same scenario will be able to arise during all phases.
//
// Here is an example using type alias `impl Trait`
// that indicates the distinction we are checking for:
//
// ```rust
// mod a {
// 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)?
} else {
self.opaque_ty_origin_unchecked(def_id, cause.span)
let origin = match self.defining_use_anchor {
DefiningAnchor::Bind(_) => {
// Check that this is `impl Trait` type is
// declared by `parent_def_id` -- i.e., one whose
// value we are inferring. At present, this is
// always true during the first phase of
// type-check, but not always true later on during
// NLL. Once we support named opaque types more fully,
// this same scenario will be able to arise during all phases.
//
// Here is an example using type alias `impl Trait`
// that indicates the distinction we are checking for:
//
// ```rust
// mod a {
// 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)?
}
DefiningAnchor::Bubble => self.opaque_ty_origin_unchecked(def_id, cause.span),
DefiningAnchor::Error => return None,
};
if let ty::Opaque(did2, _) = *b.kind() {
// We could accept this, but there are various ways to handle this situation, and we don't
@ -407,7 +409,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "trace")]
pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option<OpaqueTyOrigin> {
let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = self.defining_use_anchor?;
let parent_def_id = match self.defining_use_anchor {
DefiningAnchor::Bubble | DefiningAnchor::Error => return None,
DefiningAnchor::Bind(bind) => bind,
};
let item_kind = &self.tcx.hir().expect_item(def_id).kind;
let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item_kind else {