final assignments of the various region variables if there is some
flexibility.
-- vtable: find and records the impls to use for each trait bound that
- appears on a type parameter.
-
- writeback: writes the final types within a function body, replacing
type variables with their final inferred types. These final types
are written into the `tcx.node_types` table, which should *never* contain
};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{
- GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
-};
+use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts};
use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
use rustc_middle::ty::{
self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef,
struct ProhibitOpaqueVisitor<'tcx> {
opaque_identity_ty: Ty<'tcx>,
generics: &'tcx ty::Generics,
+ ty: Option<Ty<'tcx>>,
};
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
- if t == self.opaque_identity_ty { false } else { t.super_visit_with(self) }
+ if t != self.opaque_identity_ty && t.super_visit_with(self) {
+ self.ty = Some(t);
+ return true;
+ }
+ false
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
}
}
- let prohibit_opaque = match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy {
- origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
- ..
- }) => {
- let mut visitor = ProhibitOpaqueVisitor {
- opaque_identity_ty: tcx.mk_opaque(
- def_id.to_def_id(),
- InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
- ),
- generics: tcx.generics_of(def_id),
- };
- debug!("check_opaque_for_inheriting_lifetimes: visitor={:?}", visitor);
-
- tcx.predicates_of(def_id)
- .predicates
- .iter()
- .any(|(predicate, _)| predicate.visit_with(&mut visitor))
- }
- _ => false,
- };
-
- debug!("check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}", prohibit_opaque);
- if prohibit_opaque {
- let is_async = match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
- hir::OpaqueTyOrigin::AsyncFn => true,
- _ => false,
- },
- _ => unreachable!(),
+ if let ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
+ ..
+ }) = item.kind
+ {
+ let mut visitor = ProhibitOpaqueVisitor {
+ opaque_identity_ty: tcx.mk_opaque(
+ def_id.to_def_id(),
+ InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
+ ),
+ generics: tcx.generics_of(def_id),
+ ty: None,
};
+ let prohibit_opaque = tcx
+ .predicates_of(def_id)
+ .predicates
+ .iter()
+ .any(|(predicate, _)| predicate.visit_with(&mut visitor));
+ debug!(
+ "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
+ prohibit_opaque, visitor
+ );
- tcx.sess.span_err(
- span,
- &format!(
- "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
+ if prohibit_opaque {
+ let is_async = match item.kind {
+ ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
+ hir::OpaqueTyOrigin::AsyncFn => true,
+ _ => false,
+ },
+ _ => unreachable!(),
+ };
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0760,
+ "`{}` return type cannot contain a projection or `Self` that references lifetimes from \
a parent scope",
- if is_async { "async fn" } else { "impl Trait" },
- ),
- );
+ if is_async { "async fn" } else { "impl Trait" },
+ );
+
+ if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
+ if snippet == "Self" {
+ if let Some(ty) = visitor.ty {
+ err.span_suggestion(
+ span,
+ "consider spelling out the type instead",
+ format!("{:?}", ty),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ err.emit();
+ }
}
}
// caught by case 1.
match rty.is_representable(tcx, sp) {
Representability::SelfRecursive(spans) => {
- let mut err = recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id());
- for span in spans {
- err.span_label(span, "recursive without indirection");
- }
- err.emit();
+ recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
return false;
}
Representability::Representable | Representability::ContainsRecursive => (),
pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
let t = AstConv::ast_ty_to_ty(self, ast_t);
- self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
+ self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
t
}
pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
let c = ty::Const::from_anon_const(self.tcx, const_def_id);
-
- // HACK(eddyb) emulate what a `WellFormedConst` obligation would do.
- // This code should be replaced with the proper WF handling ASAP.
- if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val {
- assert!(promoted.is_none());
-
- // HACK(eddyb) let's hope these are always empty.
- // let obligations = self.nominal_obligations(def_id, substs);
- // self.out.extend(obligations);
-
- let cause = traits::ObligationCause::new(
- self.tcx.def_span(const_def_id.to_def_id()),
- self.body_id,
- traits::MiscObligation,
- );
- self.register_predicate(traits::Obligation::new(
- cause,
- self.param_env,
- ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx),
- ));
- }
-
+ self.register_wf_obligation(
+ c.into(),
+ self.tcx.hir().span(ast_c.hir_id),
+ ObligationCauseCode::MiscObligation,
+ );
c
}
}
}
- /// Registers an obligation for checking later, during regionck, that the type `ty` must
- /// outlive the region `r`.
+ /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
pub fn register_wf_obligation(
&self,
- ty: Ty<'tcx>,
+ arg: subst::GenericArg<'tcx>,
span: Span,
code: traits::ObligationCauseCode<'tcx>,
) {
self.register_predicate(traits::Obligation::new(
cause,
self.param_env,
- ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx),
+ ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx),
));
}
- /// Registers obligations that all types appearing in `substs` are well-formed.
+ /// Registers obligations that all `substs` are well-formed.
pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
- for ty in substs.types() {
- if !ty.references_error() {
- self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
- }
+ for arg in substs.iter().filter(|arg| {
+ matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+ }) {
+ self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
}
}
trait_ref: ty::PolyTraitRef<'tcx>,
expected_vid: ty::TyVid,
) -> bool {
- let self_ty = self.shallow_resolve(trait_ref.self_ty());
+ let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
debug!(
"self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
trait_ref, self_ty, expected_vid
// All the input types from the fn signature must outlive the call
// so as to validate implied bounds.
- for (fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
- self.register_wf_obligation(fn_input_ty, arg_expr.span, traits::MiscObligation);
+ for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
+ self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
}
let expected_arg_count = fn_inputs.len();
debug!("check_closures={}", check_closures);
// More awful hacks: before we check argument types, try to do
- // an "opportunistic" vtable resolution of any trait bounds on
+ // an "opportunistic" trait resolution of any trait bounds on
// the call. This helps coercions.
if check_closures {
self.select_obligations_where_possible(false, |errors| {