Auto merge of #67681 - matthewjasper:infer-regions-in-borrowck, r=nikomatsakis

Infer regions for opaque types in borrowck

This is a step towards the goal of typeck not doing region inference.

The commits up to `Arena allocate the result of mir_borrowck` are various bug fixes and prerequisites.
The remaining commits move opaque type inference to borrow checking.

r? @nikomatsakis
This commit is contained in:
bors 2020-02-15 02:24:04 +00:00
commit 19288ddfd6
72 changed files with 1994 additions and 1302 deletions

View File

@ -35,7 +35,8 @@ macro_rules! arena_types {
rustc::mir::Promoted,
rustc::mir::BodyAndCache<$tcx>
>,
[] tables: rustc::ty::TypeckTables<$tcx>,
[decode] tables: rustc::ty::TypeckTables<$tcx>,
[decode] borrowck_result: rustc::mir::BorrowCheckResult<$tcx>,
[] const_allocs: rustc::mir::interpret::Allocation,
[] vtable_method: Option<(
rustc_hir::def_id::DefId,

View File

@ -405,17 +405,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
RegionResolutionError::MemberConstraintFailure {
opaque_type_def_id,
hidden_ty,
member_region,
span: _,
choice_regions: _,
span,
} => {
let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
opaque_types::unexpected_hidden_region_diagnostic(
self.tcx,
Some(region_scope_tree),
opaque_type_def_id,
span,
hidden_ty,
member_region,
)

View File

@ -18,7 +18,6 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::implementation::{
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use rustc_hir::def_id::DefId;
use rustc_index::vec::{Idx, IndexVec};
use rustc_span::Span;
use std::fmt;
@ -95,13 +94,7 @@ pub enum RegionResolutionError<'tcx> {
/// Indicates a failure of a `MemberConstraint`. These arise during
/// impl trait processing explicitly -- basically, the impl trait's hidden type
/// included some region that it was not supposed to.
MemberConstraintFailure {
span: Span,
opaque_type_def_id: DefId,
hidden_ty: Ty<'tcx>,
member_region: Region<'tcx>,
choice_regions: Vec<Region<'tcx>>,
},
MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> },
}
struct RegionAndOrigin<'tcx> {
@ -656,10 +649,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
let span = self.tcx().def_span(member_constraint.opaque_type_def_id);
errors.push(RegionResolutionError::MemberConstraintFailure {
span,
opaque_type_def_id: member_constraint.opaque_type_def_id,
hidden_ty: member_constraint.hidden_ty,
member_region,
choice_regions: choice_regions.collect(),
});
}
}

View File

@ -93,6 +93,18 @@ pub struct OpaqueTypeDecl<'tcx> {
pub origin: hir::OpaqueTyOrigin,
}
/// Whether member constraints should be generated for all opaque types
pub enum GenerateMemberConstraints {
/// The default, used by typeck
WhenRequired,
/// The borrow checker needs member constraints in any case where we don't
/// have a `'static` bound. This is because the borrow checker has more
/// flexibility in the values of regions. For example, given `f<'a, 'b>`
/// the borrow checker can have an inference variable outlive `'a` and `'b`,
/// but not be equal to `'static`.
IfNoStaticBound,
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Replaces all opaque types in `value` with fresh inference variables
/// and creates appropriate obligations. For example, given the input:
@ -315,7 +327,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
debug!("constrain_opaque_types()");
for (&def_id, opaque_defn) in opaque_types {
self.constrain_opaque_type(def_id, opaque_defn, free_region_relations);
self.constrain_opaque_type(
def_id,
opaque_defn,
GenerateMemberConstraints::WhenRequired,
free_region_relations,
);
}
}
@ -324,6 +341,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
&self,
def_id: DefId,
opaque_defn: &OpaqueTypeDecl<'tcx>,
mode: GenerateMemberConstraints,
free_region_relations: &FRR,
) {
debug!("constrain_opaque_type()");
@ -358,6 +376,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
});
}
if let GenerateMemberConstraints::IfNoStaticBound = mode {
self.generate_member_constraint(
concrete_ty,
opaque_type_generics,
opaque_defn,
def_id,
);
}
return;
}
@ -398,13 +424,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// we will create a "in bound" like `'r in
// ['a, 'b, 'c]`, where `'a..'c` are the
// regions that appear in the impl trait.
// For now, enforce a feature gate outside of async functions.
self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_arg);
return self.generate_member_constraint(
concrete_ty,
opaque_type_generics,
opaque_defn,
def_id,
lr,
subst_arg,
);
}
}
@ -414,6 +442,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let least_region = least_region.unwrap_or(tcx.lifetimes.re_static);
debug!("constrain_opaque_types: least_region={:?}", least_region);
if let GenerateMemberConstraints::IfNoStaticBound = mode {
if least_region != tcx.lifetimes.re_static {
self.generate_member_constraint(
concrete_ty,
opaque_type_generics,
opaque_defn,
def_id,
);
}
}
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
tcx: self.tcx,
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
@ -434,19 +472,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
opaque_type_generics: &ty::Generics,
opaque_defn: &OpaqueTypeDecl<'tcx>,
opaque_type_def_id: DefId,
conflict1: ty::Region<'tcx>,
conflict2: ty::Region<'tcx>,
) {
// For now, enforce a feature gate outside of async functions.
if self.member_constraint_feature_gate(
opaque_defn,
opaque_type_def_id,
conflict1,
conflict2,
) {
return;
}
// Create the set of choice regions: each region in the hidden
// type can be equal to any of the region parameters of the
// opaque type definition.
@ -500,8 +526,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
hir::OpaqueTyOrigin::AsyncFn => return false,
// Otherwise, generate the label we'll use in the error message.
hir::OpaqueTyOrigin::TypeAlias => "impl Trait",
hir::OpaqueTyOrigin::FnReturn => "impl Trait",
hir::OpaqueTyOrigin::TypeAlias
| hir::OpaqueTyOrigin::FnReturn
| hir::OpaqueTyOrigin::Misc => "impl Trait",
};
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
let mut err = self.tcx.sess.struct_span_err(span, &msg);
@ -549,13 +576,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// # Parameters
///
/// - `def_id`, the `impl Trait` type
/// - `opaque_defn`, the opaque definition created in `instantiate_opaque_types`
/// - `substs`, the substs used to instantiate this opaque type
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
/// `opaque_defn.concrete_ty`
pub fn infer_opaque_definition_from_instantiation(
&self,
def_id: DefId,
opaque_defn: &OpaqueTypeDecl<'tcx>,
substs: SubstsRef<'tcx>,
instantiated_ty: Ty<'tcx>,
span: Span,
) -> Ty<'tcx> {
@ -571,12 +598,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// `impl Trait` return type, resulting in the parameters
// shifting.
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id);
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = opaque_defn
.substs
.iter()
.enumerate()
.map(|(index, subst)| (*subst, id_substs[index]))
.collect();
let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> =
substs.iter().enumerate().map(|(index, subst)| (*subst, id_substs[index])).collect();
// Convert the type from the function into a type valid outside
// the function, by replacing invalid regions with 'static,
@ -598,11 +621,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn unexpected_hidden_region_diagnostic(
tcx: TyCtxt<'tcx>,
region_scope_tree: Option<&region::ScopeTree>,
opaque_type_def_id: DefId,
span: Span,
hidden_ty: Ty<'tcx>,
hidden_region: ty::Region<'tcx>,
) -> DiagnosticBuilder<'tcx> {
let span = tcx.def_span(opaque_type_def_id);
let mut err = struct_span_err!(
tcx.sess,
span,
@ -817,32 +839,48 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match r {
// ignore bound regions that appear in the type (e.g., this
// would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
ty::ReLateBound(..) |
// Ignore bound regions and `'static` regions that appear in the
// type, we only need to remap regions that reference lifetimes
// from the function declaraion.
// This would ignore `'r` in a type like `for<'r> fn(&'r u32)`.
ty::ReLateBound(..) | ty::ReStatic => return r,
// ignore `'static`, as that can appear anywhere
ty::ReStatic => return r,
// If regions have been erased (by writeback), don't try to unerase
// them.
ty::ReErased => return r,
_ => { }
// The regions that we expect from borrow checking.
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {}
ty::ReEmpty(_)
| ty::RePlaceholder(_)
| ty::ReVar(_)
| ty::ReScope(_)
| ty::ReClosureBound(_) => {
// All of the regions in the type should either have been
// erased by writeback, or mapped back to named regions by
// borrow checking.
bug!("unexpected region kind in opaque type: {:?}", r);
}
}
let generics = self.tcx().generics_of(self.opaque_type_def_id);
match self.map.get(&r.into()).map(|k| k.unpack()) {
Some(GenericArgKind::Lifetime(r1)) => r1,
Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
None if self.map_missing_regions_to_empty || self.tainted_by_errors => {
self.tcx.lifetimes.re_root_empty
}
None if generics.parent.is_some() => {
if !self.map_missing_regions_to_empty && !self.tainted_by_errors {
if let Some(hidden_ty) = self.hidden_ty.take() {
unexpected_hidden_region_diagnostic(
self.tcx,
None,
self.opaque_type_def_id,
hidden_ty,
r,
)
.emit();
}
if let Some(hidden_ty) = self.hidden_ty.take() {
unexpected_hidden_region_diagnostic(
self.tcx,
None,
self.tcx.def_span(self.opaque_type_def_id),
hidden_ty,
r,
)
.emit();
}
self.tcx.lifetimes.re_root_empty
}
@ -860,7 +898,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> {
)
.emit();
self.tcx().mk_region(ty::ReStatic)
self.tcx().lifetimes.re_static
}
}
}

View File

@ -1,8 +1,10 @@
//! Values computed by queries that use MIR.
use crate::ty::{self, Ty};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitMatrix;
use rustc_index::vec::IndexVec;
use rustc_span::{Span, Symbol};
@ -59,8 +61,12 @@ pub struct GeneratorLayout<'tcx> {
pub storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
}
#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
#[derive(Debug, RustcEncodable, RustcDecodable, HashStable)]
pub struct BorrowCheckResult<'tcx> {
/// All the opaque types that are restricted to concrete types
/// by this function. Unlike the value in `TypeckTables`, this has
/// unerased regions.
pub concrete_opaque_types: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
pub used_mut_upvars: SmallVec<[Field; 8]>,
}

View File

@ -125,7 +125,9 @@ rustc_queries! {
/// Fetch the MIR for a given `DefId` right after it's built - this includes
/// unreachable code.
query mir_built(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {}
query mir_built(_: DefId) -> &'tcx Steal<mir::BodyAndCache<'tcx>> {
desc { "building MIR for" }
}
/// Fetch the MIR for a given `DefId` up till the point where it is
/// ready for const evaluation.
@ -345,6 +347,7 @@ rustc_queries! {
TypeChecking {
/// The result of unsafety-checking this `DefId`.
query unsafety_check_result(key: DefId) -> mir::UnsafetyCheckResult {
desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
}
@ -414,14 +417,8 @@ rustc_queries! {
}
query typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> {
desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
load_cached(tcx, id) {
let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx
.queries.on_disk_cache
.try_load_query_result(tcx, id);
typeck_tables.map(|tables| &*tcx.arena.alloc(tables))
}
}
query diagnostic_only_typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> {
cache_on_disk_if { key.is_local() }
@ -452,8 +449,13 @@ rustc_queries! {
BorrowChecking {
/// Borrow-checks the function body. If this is a closure, returns
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: DefId) -> mir::BorrowCheckResult<'tcx> {
cache_on_disk_if(tcx, _) { key.is_local() && tcx.is_closure(key) }
query mir_borrowck(key: DefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if(tcx, opt_result) {
key.is_local()
&& (tcx.is_closure(key)
|| opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty()))
}
}
}

View File

@ -138,7 +138,7 @@ impl FlagComputation {
}
&ty::Opaque(_, substs) => {
self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_flags(TypeFlags::HAS_PROJECTION | TypeFlags::HAS_TY_OPAQUE);
self.add_substs(substs);
}

View File

@ -78,6 +78,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn has_projections(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION)
}
fn has_opaque_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
}
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_ERR)
}
@ -120,6 +123,10 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
}
fn has_erased_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_ERASED)
}
/// True if there are any un-erased free regions.
fn has_erasable_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)

View File

@ -474,10 +474,15 @@ bitflags! {
/// if a global bound is safe to evaluate.
const HAS_RE_LATE_BOUND = 1 << 11;
const HAS_TY_PLACEHOLDER = 1 << 12;
/// Does this have any `ReErased` regions?
const HAS_RE_ERASED = 1 << 12;
const HAS_CT_INFER = 1 << 13;
const HAS_CT_PLACEHOLDER = 1 << 14;
const HAS_TY_PLACEHOLDER = 1 << 13;
const HAS_CT_INFER = 1 << 14;
const HAS_CT_PLACEHOLDER = 1 << 15;
/// Does this have any [Opaque] types.
const HAS_TY_OPAQUE = 1 << 16;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits;
@ -497,9 +502,11 @@ bitflags! {
TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
TypeFlags::HAS_RE_LATE_BOUND.bits |
TypeFlags::HAS_RE_ERASED.bits |
TypeFlags::HAS_TY_PLACEHOLDER.bits |
TypeFlags::HAS_CT_INFER.bits |
TypeFlags::HAS_CT_PLACEHOLDER.bits;
TypeFlags::HAS_CT_PLACEHOLDER.bits |
TypeFlags::HAS_TY_OPAQUE.bits;
}
}

View File

@ -1777,7 +1777,9 @@ impl RegionKind {
ty::ReEmpty(_) | ty::ReStatic | ty::ReFree { .. } | ty::ReScope { .. } => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
ty::ReErased => {}
ty::ReErased => {
flags = flags | TypeFlags::HAS_RE_ERASED;
}
ty::ReClosureBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}

View File

@ -615,7 +615,7 @@ impl<'tcx> TyCtxt<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Opaque(def_id, substs) = t.kind {
self.expand_opaque_ty(def_id, substs).unwrap_or(t)
} else if t.has_projections() {
} else if t.has_opaque_types() {
t.super_fold_with(self)
} else {
t

View File

@ -272,7 +272,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ty = self.lower_ty(
t,
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::OpaqueTy(None)
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
},
@ -283,7 +283,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ty = self.lower_ty(
t,
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::OpaqueTy(None)
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc)
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
},
@ -327,8 +327,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
Some(bounds) => {
let ty = hir::OpaqueTy {
generics: self.lower_generics(generics, ImplTraitContext::OpaqueTy(None)),
bounds: self.lower_param_bounds(bounds, ImplTraitContext::OpaqueTy(None)),
generics: self.lower_generics(
generics,
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc),
),
bounds: self.lower_param_bounds(
bounds,
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc),
),
impl_trait_fn: None,
origin: hir::OpaqueTyOrigin::TypeAlias,
};

View File

@ -222,7 +222,7 @@ enum ImplTraitContext<'b, 'a> {
/// We optionally store a `DefId` for the parent item here so we can look up necessary
/// information later. It is `None` when no information about the context should be stored
/// (e.g., for consts and statics).
OpaqueTy(Option<DefId> /* fn def-ID */),
OpaqueTy(Option<DefId> /* fn def-ID */, hir::OpaqueTyOrigin),
/// `impl Trait` is not accepted in this position.
Disallowed(ImplTraitPosition),
@ -248,7 +248,7 @@ impl<'a> ImplTraitContext<'_, 'a> {
use self::ImplTraitContext::*;
match self {
Universal(params) => Universal(params),
OpaqueTy(fn_def_id) => OpaqueTy(*fn_def_id),
OpaqueTy(fn_def_id, origin) => OpaqueTy(*fn_def_id, *origin),
Disallowed(pos) => Disallowed(*pos),
}
}
@ -1010,7 +1010,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// so desugar to
//
// fn foo() -> impl Iterator<Item = impl Debug>
ImplTraitContext::OpaqueTy(_) => (true, itctx),
ImplTraitContext::OpaqueTy(..) => (true, itctx),
// We are in the argument position, but within a dyn type:
//
@ -1019,7 +1019,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// so desugar to
//
// fn foo(x: dyn Iterator<Item = impl Debug>)
ImplTraitContext::Universal(_) if self.is_in_dyn_type => (true, itctx),
ImplTraitContext::Universal(..) if self.is_in_dyn_type => (true, itctx),
// In `type Foo = dyn Iterator<Item: Debug>` we desugar to
// `type Foo = dyn Iterator<Item = impl Debug>` but we have to override the
@ -1028,7 +1028,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
//
// FIXME: this is only needed until `impl Trait` is allowed in type aliases.
ImplTraitContext::Disallowed(_) if self.is_in_dyn_type => {
(true, ImplTraitContext::OpaqueTy(None))
(true, ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc))
}
// We are in the parameter position, but not within a dyn type:
@ -1269,8 +1269,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::ImplTrait(def_node_id, ref bounds) => {
let span = t.span;
match itctx {
ImplTraitContext::OpaqueTy(fn_def_id) => {
self.lower_opaque_impl_trait(span, fn_def_id, def_node_id, |this| {
ImplTraitContext::OpaqueTy(fn_def_id, origin) => {
self.lower_opaque_impl_trait(span, fn_def_id, origin, def_node_id, |this| {
this.lower_param_bounds(bounds, itctx)
})
}
@ -1349,6 +1349,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
span: Span,
fn_def_id: Option<DefId>,
origin: hir::OpaqueTyOrigin,
opaque_ty_node_id: NodeId,
lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
) -> hir::TyKind<'hir> {
@ -1390,7 +1391,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
},
bounds: hir_bounds,
impl_trait_fn: fn_def_id,
origin: hir::OpaqueTyOrigin::FnReturn,
origin,
};
trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_index);
@ -1622,7 +1623,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_ty(
t,
if self.sess.features_untracked().impl_trait_in_bindings {
ImplTraitContext::OpaqueTy(Some(parent_def_id))
ImplTraitContext::OpaqueTy(Some(parent_def_id), hir::OpaqueTyOrigin::Misc)
} else {
ImplTraitContext::Disallowed(ImplTraitPosition::Binding)
},
@ -1722,14 +1723,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
} else {
match decl.output {
FunctionRetTy::Ty(ref ty) => match in_band_ty_params {
Some((def_id, _)) if impl_trait_return_allow => hir::FunctionRetTy::Return(
self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(def_id))),
),
_ => hir::FunctionRetTy::Return(
self.lower_ty(ty, ImplTraitContext::disallowed()),
),
},
FunctionRetTy::Ty(ref ty) => {
let context = match in_band_ty_params {
Some((def_id, _)) if impl_trait_return_allow => {
ImplTraitContext::OpaqueTy(Some(def_id), hir::OpaqueTyOrigin::FnReturn)
}
_ => ImplTraitContext::disallowed(),
};
hir::FunctionRetTy::Return(self.lower_ty(ty, context))
}
FunctionRetTy::Default(span) => hir::FunctionRetTy::DefaultReturn(span),
}
};
@ -1957,7 +1959,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::GenericBound<'hir> {
// Compute the `T` in `Future<Output = T>` from the return type.
let output_ty = match output {
FunctionRetTy::Ty(ty) => self.lower_ty(ty, ImplTraitContext::OpaqueTy(Some(fn_def_id))),
FunctionRetTy::Ty(ty) => {
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
// `impl Future` opaque type that `async fn` implicitly
// generates.
let context =
ImplTraitContext::OpaqueTy(Some(fn_def_id), hir::OpaqueTyOrigin::FnReturn);
self.lower_ty(ty, context)
}
FunctionRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
};
@ -2102,9 +2111,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
let kind = hir::GenericParamKind::Type {
default: default
.as_ref()
.map(|x| self.lower_ty(x, ImplTraitContext::OpaqueTy(None))),
default: default.as_ref().map(|x| {
self.lower_ty(
x,
ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc),
)
}),
synthetic: param
.attrs
.iter()

View File

@ -1990,6 +1990,8 @@ pub enum OpaqueTyOrigin {
FnReturn,
/// `async fn`
AsyncFn,
/// Impl trait in bindings, consts, statics, bounds.
Misc,
}
/// The various kinds of types recognized by the compiler.

View File

@ -6,7 +6,6 @@ use rustc::infer::{
use rustc::mir::ConstraintCategory;
use rustc::ty::{self, RegionVid, Ty};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir::def_id::DefId;
use rustc_span::symbol::kw;
use rustc_span::Span;
@ -58,8 +57,8 @@ crate enum RegionErrorKind<'tcx> {
/// An unexpected hidden region for an opaque type.
UnexpectedHiddenRegion {
/// The def id of the opaque type.
opaque_type_def_id: DefId,
/// The span for the member constraint.
span: Span,
/// The hidden type.
hidden_ty: Ty<'tcx>,
/// The unexpected region.
@ -194,18 +193,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
RegionErrorKind::UnexpectedHiddenRegion {
opaque_type_def_id,
hidden_ty,
member_region,
} => {
RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
opaque_types::unexpected_hidden_region_diagnostic(
self.infcx.tcx,
Some(region_scope_tree),
opaque_type_def_id,
hidden_ty,
member_region,
span,
named_ty,
named_region,
)
.buffer(&mut self.errors_buffer);
}
@ -588,6 +585,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
{
found = true;
break;
} else {
// If there's already a lifetime bound, don't
// suggest anything.
return;
}
}
}

View File

@ -90,7 +90,7 @@ pub fn provide(providers: &mut Providers<'_>) {
*providers = Providers { mir_borrowck, ..*providers };
}
fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> {
fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> &BorrowCheckResult<'_> {
let (input_body, promoted) = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
@ -101,7 +101,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def_id: DefId) -> BorrowCheckResult<'_> {
});
debug!("mir_borrowck done");
opt_closure_req
tcx.arena.alloc(opt_closure_req)
}
fn do_mir_borrowck<'a, 'tcx>(
@ -136,6 +136,9 @@ fn do_mir_borrowck<'a, 'tcx>(
// Gather the upvars of a closure, if any.
let tables = tcx.typeck_tables_of(def_id);
if tables.tainted_by_errors {
infcx.set_tainted_by_errors();
}
let upvars: Vec<_> = tables
.upvar_list
.get(&def_id)
@ -195,27 +198,40 @@ fn do_mir_borrowck<'a, 'tcx>(
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
// Compute non-lexical lifetimes.
let nll::NllOutput { regioncx, polonius_output, opt_closure_req, nll_errors } =
nll::compute_regions(
infcx,
def_id,
free_regions,
body,
&promoted,
location_table,
param_env,
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
);
let nll::NllOutput {
regioncx,
opaque_type_values,
polonius_output,
opt_closure_req,
nll_errors,
} = nll::compute_regions(
infcx,
def_id,
free_regions,
body,
&promoted,
location_table,
param_env,
&mut flow_inits,
&mdpe.move_data,
&borrow_set,
);
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests, as well as helping with debugging.
nll::dump_mir_results(infcx, MirSource::item(def_id), &body, &regioncx, &opt_closure_req);
// We also have a `#[rustc_nll]` annotation that causes us to dump
// We also have a `#[rustc_regions]` annotation that causes us to dump
// information.
nll::dump_annotation(infcx, &body, def_id, &regioncx, &opt_closure_req, &mut errors_buffer);
nll::dump_annotation(
infcx,
&body,
def_id,
&regioncx,
&opt_closure_req,
&opaque_type_values,
&mut errors_buffer,
);
// The various `flow_*` structures can be large. We drop `flow_inits` here
// so it doesn't overlap with the others below. This reduces peak memory
@ -389,6 +405,7 @@ fn do_mir_borrowck<'a, 'tcx>(
}
let result = BorrowCheckResult {
concrete_opaque_types: opaque_type_values,
closure_requirements: opt_closure_req,
used_mut_upvars: mbcx.used_mut_upvars,
};

View File

@ -6,6 +6,7 @@ use rustc::mir::{
Location, Promoted, ReadOnlyBodyAndCache,
};
use rustc::ty::{self, RegionKind, RegionVid};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::DefId;
use rustc_index::vec::IndexVec;
@ -46,6 +47,7 @@ crate type PoloniusOutput = Output<RustcFacts>;
/// closure requirements to propagate, and any generated errors.
crate struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>,
pub opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
pub polonius_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
pub nll_errors: RegionErrors<'tcx>,
@ -160,20 +162,21 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
let elements = &Rc::new(RegionValueElements::new(&body));
// Run the MIR type-checker.
let MirTypeckResults { constraints, universal_region_relations } = type_check::type_check(
infcx,
param_env,
body,
promoted,
def_id,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
);
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
type_check::type_check(
infcx,
param_env,
body,
promoted,
def_id,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
);
if let Some(all_facts) = &mut all_facts {
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
@ -279,8 +282,16 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
let (closure_region_requirements, nll_errors) =
regioncx.solve(infcx, &body, def_id, polonius_output.clone());
if !nll_errors.is_empty() {
// Suppress unhelpful extra errors in `infer_opaque_types`.
infcx.set_tainted_by_errors();
}
let remapped_opaque_tys = regioncx.infer_opaque_types(&infcx, opaque_type_values, body.span);
NllOutput {
regioncx,
opaque_type_values: remapped_opaque_tys,
polonius_output,
opt_closure_req: closure_region_requirements,
nll_errors,
@ -344,6 +355,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
mir_def_id: DefId,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
opaque_type_values: &FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
errors_buffer: &mut Vec<Diagnostic>,
) {
let tcx = infcx.tcx;
@ -359,7 +371,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
// viewing the intraprocedural state, the -Zdump-mir output is
// better.
if let Some(closure_region_requirements) = closure_region_requirements {
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "external requirements");
regioncx.annotate(tcx, &mut err);
@ -377,13 +389,19 @@ pub(super) fn dump_annotation<'a, 'tcx>(
})
.unwrap();
err.buffer(errors_buffer);
err
} else {
let mut err = tcx.sess.diagnostic().span_note_diag(body.span, "no external requirements");
regioncx.annotate(tcx, &mut err);
err.buffer(errors_buffer);
err
};
if !opaque_type_values.is_empty() {
err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values));
}
err.buffer(errors_buffer);
}
fn for_each_region_constraint(

View File

@ -12,8 +12,6 @@ use rustc::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc_data_structures::binary_search_util;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_data_structures::graph::vec_graph::VecGraph;
use rustc_data_structures::graph::WithSuccessors;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
@ -26,6 +24,7 @@ use crate::borrow_check::{
diagnostics::{RegionErrorKind, RegionErrors},
member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
nll::{PoloniusOutput, ToRegionVid},
region_infer::reverse_sccs::ReverseSccGraph,
region_infer::values::{
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
ToElementIndex,
@ -36,6 +35,8 @@ use crate::borrow_check::{
mod dump_mir;
mod graphviz;
mod opaque_types;
mod reverse_sccs;
pub mod values;
@ -65,9 +66,10 @@ pub struct RegionInferenceContext<'tcx> {
/// compute the values of each region.
constraint_sccs: Rc<Sccs<RegionVid, ConstraintSccIndex>>,
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B`
/// exists if `B: A`. Computed lazilly.
rev_constraint_graph: Option<Rc<VecGraph<ConstraintSccIndex>>>,
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
/// `B: A`. This is used to compute the universal regions that are required
/// to outlive a given SCC. Computed lazily.
rev_scc_graph: Option<Rc<ReverseSccGraph>>,
/// The "R0 member of [R1..Rn]" constraints, indexed by SCC.
member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
@ -287,7 +289,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
constraints,
constraint_graph,
constraint_sccs,
rev_constraint_graph: None,
rev_scc_graph: None,
member_constraints,
member_constraints_applied: Vec::new(),
closure_bounds_mapping,
@ -510,7 +512,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.check_universal_regions(body, outlives_requirements.as_mut(), &mut errors_buffer);
}
self.check_member_constraints(infcx, &mut errors_buffer);
if errors_buffer.is_empty() {
self.check_member_constraints(infcx, &mut errors_buffer);
}
let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
@ -677,15 +681,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// free region that must outlive the member region `R0` (`UB:
// R0`). Therefore, we need only keep an option `O` if `UB: O`
// for all UB.
if choice_regions.len() > 1 {
let universal_region_relations = self.universal_region_relations.clone();
let rev_constraint_graph = self.rev_constraint_graph();
for ub in self.upper_bounds(scc, &rev_constraint_graph) {
debug!("apply_member_constraint: ub={:?}", ub);
choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
}
debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions);
let rev_scc_graph = self.reverse_scc_graph();
let universal_region_relations = &self.universal_region_relations;
for ub in rev_scc_graph.upper_bounds(scc) {
debug!("apply_member_constraint: ub={:?}", ub);
choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
}
debug!("apply_member_constraint: after ub, choice_regions={:?}", choice_regions);
// If we ruled everything out, we're done.
if choice_regions.is_empty() {
@ -741,32 +743,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
}
}
/// Compute and return the reverse SCC-based constraint graph (lazilly).
fn upper_bounds(
&'a mut self,
scc0: ConstraintSccIndex,
rev_constraint_graph: &'a VecGraph<ConstraintSccIndex>,
) -> impl Iterator<Item = RegionVid> + 'a {
let scc_values = &self.scc_values;
let mut duplicates = FxHashSet::default();
rev_constraint_graph
.depth_first_search(scc0)
.skip(1)
.flat_map(move |scc1| scc_values.universal_regions_outlived_by(scc1))
.filter(move |&r| duplicates.insert(r))
}
/// Compute and return the reverse SCC-based constraint graph (lazilly).
fn rev_constraint_graph(&mut self) -> Rc<VecGraph<ConstraintSccIndex>> {
if let Some(g) = &self.rev_constraint_graph {
return g.clone();
}
let rev_graph = Rc::new(self.constraint_sccs.reverse());
self.rev_constraint_graph = Some(rev_graph.clone());
rev_graph
}
/// Returns `true` if all the elements in the value of `scc_b` are nameable
/// in `scc_a`. Used during constraint propagation, and only once
/// the value of `scc_b` has been computed.
@ -1603,7 +1579,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// If not, report an error.
let member_region = infcx.tcx.mk_region(ty::ReVar(member_region_vid));
errors_buffer.push(RegionErrorKind::UnexpectedHiddenRegion {
opaque_type_def_id: m_c.opaque_type_def_id,
span: m_c.definition_span,
hidden_ty: m_c.hidden_ty,
member_region,
});

View File

@ -0,0 +1,149 @@
use rustc::infer::InferCtxt;
use rustc::ty::{self, TyCtxt, TypeFoldable};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_span::Span;
use super::RegionInferenceContext;
impl<'tcx> RegionInferenceContext<'tcx> {
/// Resolve any opaque types that were encountered while borrow checking
/// this item. This is then used to get the type in the `type_of` query.
///
/// For example consider `fn f<'a>(x: &'a i32) -> impl Sized + 'a { x }`.
/// This is lowered to give HIR something like
///
/// type f<'a>::_Return<'_a> = impl Sized + '_a;
/// fn f<'a>(x: &'a i32) -> f<'static>::_Return<'a> { x }
///
/// When checking the return type record the type from the return and the
/// type used in the return value. In this case they might be `_Return<'1>`
/// and `&'2 i32` respectively.
///
/// Once we to this method, we have completed region inference and want to
/// call `infer_opaque_definition_from_instantiation` to get the inferred
/// type of `_Return<'_a>`. `infer_opaque_definition_from_instantiation`
/// compares lifetimes directly, so we need to map the inference variables
/// back to concrete lifetimes: `'static`, `ReEarlyBound` or `ReFree`.
///
/// First we map all the lifetimes in the concrete type to an equal
/// universal region that occurs in the concrete type's substs, in this case
/// this would result in `&'1 i32`. We only consider regions in the substs
/// in case there is an equal region that does not. For example, this should
/// be allowed:
/// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }`
///
/// Then we map the regions in both the type and the subst to their
/// `external_name` giving `concrete_type = &'a i32`,
/// `substs = ['static, 'a]`. This will then allow
/// `infer_opaque_definition_from_instantiation` to determine that
/// `_Return<'_a> = &'_a i32`.
///
/// There's a slight complication around closures. Given
/// `fn f<'a: 'a>() { || {} }` the closure's type is something like
/// `f::<'a>::{{closure}}`. The region parameter from f is essentially
/// ignored by type checking so ends up being inferred to an empty region.
/// Calling `universal_upper_bound` for such a region gives `fr_fn_body`,
/// which has no `external_name` in which case we use `'empty` as the
/// region to pass to `infer_opaque_definition_from_instantiation`.
pub(in crate::borrow_check) fn infer_opaque_types(
&self,
infcx: &InferCtxt<'_, 'tcx>,
opaque_ty_decls: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
span: Span,
) -> FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>> {
opaque_ty_decls
.into_iter()
.map(|(opaque_def_id, ty::ResolvedOpaqueTy { concrete_type, substs })| {
debug!(
"infer_opaque_types(concrete_type = {:?}, substs = {:?})",
concrete_type, substs
);
let mut subst_regions = vec![self.universal_regions.fr_static];
let universal_substs =
infcx.tcx.fold_regions(&substs, &mut false, |region, _| match *region {
ty::ReVar(vid) => {
subst_regions.push(vid);
self.definitions[vid].external_name.unwrap_or_else(|| {
infcx.tcx.sess.delay_span_bug(
span,
"opaque type with non-universal region substs",
);
infcx.tcx.lifetimes.re_static
})
}
// We don't fold regions in the predicates of opaque
// types to `ReVar`s. This means that in a case like
//
// fn f<'a: 'a>() -> impl Iterator<Item = impl Sized>
//
// The inner opaque type has `'static` in its substs.
ty::ReStatic => region,
_ => {
infcx.tcx.sess.delay_span_bug(
span,
&format!("unexpected concrete region in borrowck: {:?}", region),
);
region
}
});
subst_regions.sort();
subst_regions.dedup();
let universal_concrete_type =
infcx.tcx.fold_regions(&concrete_type, &mut false, |region, _| match *region {
ty::ReVar(vid) => subst_regions
.iter()
.find(|ur_vid| self.eval_equal(vid, **ur_vid))
.and_then(|ur_vid| self.definitions[*ur_vid].external_name)
.unwrap_or(infcx.tcx.lifetimes.re_root_empty),
ty::ReLateBound(..) => region,
_ => {
infcx.tcx.sess.delay_span_bug(
span,
&format!("unexpected concrete region in borrowck: {:?}", region),
);
region
}
});
debug!(
"infer_opaque_types(universal_concrete_type = {:?}, universal_substs = {:?})",
universal_concrete_type, universal_substs
);
let remapped_type = infcx.infer_opaque_definition_from_instantiation(
opaque_def_id,
universal_substs,
universal_concrete_type,
span,
);
(
opaque_def_id,
ty::ResolvedOpaqueTy { concrete_type: remapped_type, substs: universal_substs },
)
})
.collect()
}
/// Map the regions in the type to named regions. This is similar to what
/// `infer_opaque_types` does, but can infer any universal region, not only
/// ones from the substs for the opaque type. It also doesn't double check
/// that the regions produced are in fact equal to the named region they are
/// replaced with. This is fine because this function is only to improve the
/// region names in error messages.
pub(in crate::borrow_check) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
where
T: TypeFoldable<'tcx>,
{
tcx.fold_regions(&ty, &mut false, |region, _| match *region {
ty::ReVar(vid) => {
let upper_bound = self.universal_upper_bound(vid);
self.definitions[upper_bound].external_name.unwrap_or(region)
}
_ => region,
})
}
}

View File

@ -0,0 +1,68 @@
use crate::borrow_check::constraints::ConstraintSccIndex;
use crate::borrow_check::RegionInferenceContext;
use itertools::Itertools;
use rustc::ty::RegionVid;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::vec_graph::VecGraph;
use rustc_data_structures::graph::WithSuccessors;
use std::ops::Range;
use std::rc::Rc;
crate struct ReverseSccGraph {
graph: VecGraph<ConstraintSccIndex>,
/// For each SCC, the range of `universal_regions` that use that SCC as
/// their value.
scc_regions: FxHashMap<ConstraintSccIndex, Range<usize>>,
/// All of the universal regions, in grouped so that `scc_regions` can
/// index into here.
universal_regions: Vec<RegionVid>,
}
impl ReverseSccGraph {
/// Find all universal regions that are required to outlive the given SCC.
pub(super) fn upper_bounds<'a>(
&'a self,
scc0: ConstraintSccIndex,
) -> impl Iterator<Item = RegionVid> + 'a {
let mut duplicates = FxHashSet::default();
self.graph
.depth_first_search(scc0)
.flat_map(move |scc1| {
self.scc_regions
.get(&scc1)
.map_or(&[][..], |range| &self.universal_regions[range.clone()])
})
.copied()
.filter(move |r| duplicates.insert(*r))
}
}
impl RegionInferenceContext<'_> {
/// Compute and return the reverse SCC-based constraint graph (lazily).
pub(super) fn reverse_scc_graph(&mut self) -> Rc<ReverseSccGraph> {
if let Some(g) = &self.rev_scc_graph {
return g.clone();
}
let graph = self.constraint_sccs.reverse();
let mut paired_scc_regions = self
.universal_regions
.universal_regions()
.map(|region| (self.constraint_sccs.scc(region), region))
.collect_vec();
paired_scc_regions.sort();
let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect();
let mut scc_regions = FxHashMap::default();
let mut start = 0;
for (scc, group) in &paired_scc_regions.into_iter().group_by(|(scc, _)| *scc) {
let group_size = group.into_iter().count();
scc_regions.insert(scc, start..start + group_size);
start += group_size;
}
let rev_graph = Rc::new(ReverseSccGraph { graph, scc_regions, universal_regions });
self.rev_scc_graph = Some(rev_graph.clone());
rev_graph
}
}

View File

@ -6,6 +6,7 @@ use std::{fmt, iter, mem};
use either::Either;
use rustc::infer::canonical::QueryRegionConstraints;
use rustc::infer::opaque_types::GenerateMemberConstraints;
use rustc::infer::outlives::env::RegionBoundPairs;
use rustc::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin};
@ -158,7 +159,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
constraints: &mut constraints,
};
type_check_internal(
let opaque_type_values = type_check_internal(
infcx,
mir_def_id,
param_env,
@ -173,10 +174,11 @@ 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
},
);
MirTypeckResults { constraints, universal_region_relations }
MirTypeckResults { constraints, universal_region_relations, opaque_type_values }
}
fn type_check_internal<'a, 'tcx, R>(
@ -189,7 +191,7 @@ fn type_check_internal<'a, 'tcx, R>(
implicit_region_bound: ty::Region<'tcx>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
mut extra: impl FnMut(&mut TypeChecker<'a, 'tcx>) -> R,
extra: impl FnOnce(TypeChecker<'a, 'tcx>) -> R,
) -> R {
let mut checker = TypeChecker::new(
infcx,
@ -212,7 +214,7 @@ fn type_check_internal<'a, 'tcx, R>(
checker.typeck_mir(body);
}
extra(&mut checker)
extra(checker)
}
fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
@ -799,6 +801,7 @@ struct TypeChecker<'a, 'tcx> {
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
}
struct BorrowCheckContext<'a, 'tcx> {
@ -812,6 +815,7 @@ struct BorrowCheckContext<'a, 'tcx> {
crate struct MirTypeckResults<'tcx> {
crate constraints: MirTypeckRegionConstraints<'tcx>,
crate universal_region_relations: Rc<UniversalRegionRelations<'tcx>>,
crate opaque_type_values: FxHashMap<DefId, ty::ResolvedOpaqueTy<'tcx>>,
}
/// A collection of region constraints that must be satisfied for the
@ -958,6 +962,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
borrowck_context,
reported_errors: Default::default(),
universal_region_relations,
opaque_type_values: FxHashMap::default(),
};
checker.check_user_type_annotations();
checker
@ -1191,10 +1196,29 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
anon_ty={:?})",
revealed_ty, anon_ty
);
// Fast path for the common case.
if !anon_ty.has_opaque_types() {
if let Err(terr) = self.eq_types(anon_ty, revealed_ty, locations, category) {
span_mirbug!(
self,
locations,
"eq_opaque_type_and_type: `{:?}=={:?}` failed with `{:?}`",
revealed_ty,
anon_ty,
terr
);
}
return Ok(());
}
let infcx = self.infcx;
let tcx = infcx.tcx;
let param_env = self.param_env;
let body = self.body;
let concrete_opaque_types = &tcx.typeck_tables_of(anon_owner_def_id).concrete_opaque_types;
let mut opaque_type_values = Vec::new();
debug!("eq_opaque_type_and_type: mir_def_id={:?}", self.mir_def_id);
let opaque_type_map = self.fully_perform_op(
locations,
@ -1219,6 +1243,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
revealed_ty={:?}",
output_ty, opaque_type_map, revealed_ty
);
// Make sure that the inferred types are well-formed. I'm
// not entirely sure this is needed (the HIR type check
// didn't do this) but it seems sensible to prevent opaque
// types hiding ill-formed types.
obligations.obligations.push(traits::Obligation::new(
ObligationCause::dummy(),
param_env,
ty::Predicate::WellFormed(revealed_ty),
));
obligations.add(
infcx
.at(&ObligationCause::dummy(), param_env)
@ -1226,47 +1259,76 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
);
for (&opaque_def_id, opaque_decl) in &opaque_type_map {
let opaque_defn_ty = tcx.type_of(opaque_def_id);
let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs);
let opaque_defn_ty = renumber::renumber_regions(infcx, &opaque_defn_ty);
let concrete_is_opaque = infcx
.resolve_vars_if_possible(&opaque_decl.concrete_ty)
.is_impl_trait();
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_def_id
} else {
false
};
let opaque_defn_ty = match concrete_opaque_types.get(&opaque_def_id) {
None => {
if !concrete_is_opaque {
tcx.sess.delay_span_bug(
body.span,
&format!(
"Non-defining use of {:?} with revealed type",
opaque_def_id,
),
);
}
continue;
}
Some(opaque_defn_ty) => opaque_defn_ty,
};
debug!("opaque_defn_ty = {:?}", opaque_defn_ty);
let subst_opaque_defn_ty =
opaque_defn_ty.concrete_type.subst(tcx, opaque_decl.substs);
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_is_opaque={}",
opaque_decl.concrete_ty,
infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty),
opaque_defn_ty,
concrete_is_opaque
"eq_opaque_type_and_type: concrete_ty={:?}={:?} opaque_defn_ty={:?}",
opaque_decl.concrete_ty, resolved_ty, renumbered_opaque_defn_ty,
);
// concrete_is_opaque is `true` when 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
if !concrete_is_opaque {
// Equate concrete_ty (an inference variable) with
// the renumbered type from typeck.
obligations.add(
infcx
.at(&ObligationCause::dummy(), param_env)
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
.eq(opaque_decl.concrete_ty, renumbered_opaque_defn_ty)?,
);
opaque_type_values.push((
opaque_def_id,
ty::ResolvedOpaqueTy {
concrete_type: renumbered_opaque_defn_ty,
substs: opaque_decl.substs,
},
));
} 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_def_id,
);
}
}
@ -1282,6 +1344,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
),
)?;
self.opaque_type_values.extend(opaque_type_values);
let universal_region_relations = self.universal_region_relations;
// Finally, if we instantiated the anon types successfully, we
@ -1298,6 +1362,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
infcx.constrain_opaque_type(
opaque_def_id,
&opaque_decl,
GenerateMemberConstraints::IfNoStaticBound,
universal_region_relations,
);
Ok(InferOk { value: (), obligations: vec![] })
@ -2512,7 +2577,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
substs: SubstsRef<'tcx>,
location: Location,
) -> ty::InstantiatedPredicates<'tcx> {
if let Some(closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements {
if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements
{
let closure_constraints = QueryRegionConstraints {
outlives: closure_region_requirements.apply_requirements(tcx, def_id, substs),

View File

@ -178,6 +178,16 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
}
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
// prevent
// * `&mut x.field`
// * `x.field = y;`
// * `&x.field` if `field`'s type has interior mutability
// because either of these would allow modifying the layout constrained field and
// insert values that violate the layout constraints.
if context.is_mutating_use() || context.is_borrow() {
self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
}
for (i, elem) in place.projection.iter().enumerate() {
let proj_base = &place.projection[..i];
@ -198,24 +208,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
);
}
}
let is_borrow_of_interior_mut = context.is_borrow()
&& !Place::ty_from(place.local, proj_base, self.body, self.tcx).ty.is_freeze(
self.tcx,
self.param_env,
self.source_info.span,
);
// prevent
// * `&mut x.field`
// * `x.field = y;`
// * `&x.field` if `field`'s type has interior mutability
// because either of these would allow modifying the layout constrained field and
// insert values that violate the layout constraints.
if context.is_mutating_use() || is_borrow_of_interior_mut {
self.check_mut_borrowing_layout_constrained_field(place, context.is_mutating_use());
}
let old_source_info = self.source_info;
if let (local, []) = (&place.local, proj_base) {
let decl = &self.body.local_decls[*local];
if let [] = proj_base {
let decl = &self.body.local_decls[place.local];
if decl.internal {
if let LocalInfo::StaticRef { def_id, .. } = decl.local_info {
if self.tcx.is_mutable_static(def_id) {
@ -240,7 +235,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
// Internal locals are used in the `move_val_init` desugaring.
// We want to check unsafety against the source info of the
// desugaring, rather than the source info of the RHS.
self.source_info = self.body.local_decls[*local].source_info;
self.source_info = self.body.local_decls[place.local].source_info;
}
}
}
@ -396,6 +391,9 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
cursor = proj_base;
match elem {
// Modifications behind a dereference don't affect the value of
// the pointer.
ProjectionElem::Deref => return,
ProjectionElem::Field(..) => {
let ty =
Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty;
@ -409,7 +407,14 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
"mutating layout constrained fields cannot statically be \
checked for valid values",
)
} else {
// Check `is_freeze` as late as possible to avoid cycle errors
// with opaque types.
} else if !place.ty(self.body, self.tcx).ty.is_freeze(
self.tcx,
self.param_env,
self.source_info.span,
) {
(
"borrow of layout constrained field with interior \
mutability",
@ -417,6 +422,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
lose the constraints. Coupled with interior mutability, \
the field can be changed to invalid values",
)
} else {
continue;
};
self.require_unsafe(
description,

View File

@ -670,14 +670,51 @@ fn construct_const<'a, 'tcx>(
builder.finish()
}
/// Construct MIR for a item that has had errors in type checking.
///
/// This is required because we may still want to run MIR passes on an item
/// with type errors, but normal MIR construction can't handle that in general.
fn construct_error<'a, 'tcx>(hir: Cx<'a, 'tcx>, body_id: hir::BodyId) -> Body<'tcx> {
let owner_id = hir.tcx().hir().body_owner(body_id);
let span = hir.tcx().hir().span(owner_id);
let ty = hir.tcx().types.err;
let mut builder = Builder::new(hir, span, 0, Safety::Safe, ty, span, None);
let tcx = hir.tcx();
let owner_id = tcx.hir().body_owner(body_id);
let span = tcx.hir().span(owner_id);
let ty = tcx.types.err;
let num_params = match hir.body_owner_kind {
hir::BodyOwnerKind::Fn => tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len(),
hir::BodyOwnerKind::Closure => {
if tcx.hir().body(body_id).generator_kind().is_some() {
// Generators have an implicit `self` parameter *and* a possibly
// implicit resume parameter.
2
} else {
// The implicit self parameter adds another local in MIR.
1 + tcx.hir().fn_decl_by_hir_id(owner_id).unwrap().inputs.len()
}
}
hir::BodyOwnerKind::Const => 0,
hir::BodyOwnerKind::Static(_) => 0,
};
let mut builder = Builder::new(hir, span, num_params, Safety::Safe, ty, span, None);
let source_info = builder.source_info(span);
// Some MIR passes will expect the number of parameters to match the
// function declaration.
for _ in 0..num_params {
builder.local_decls.push(LocalDecl {
mutability: Mutability::Mut,
ty,
user_ty: UserTypeProjections::none(),
source_info,
internal: false,
local_info: LocalInfo::Other,
is_block_tail: None,
});
}
builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
builder.finish()
let mut body = builder.finish();
if tcx.hir().body(body_id).generator_kind.is_some() {
body.yield_ty = Some(ty);
}
body
}
impl<'a, 'tcx> Builder<'a, 'tcx> {

View File

@ -426,7 +426,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn visit_opaque_types(&mut self, span: Span) {
for (&def_id, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap();
let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id);
let instantiated_ty =
self.tcx().erase_regions(&self.resolve(&opaque_defn.concrete_ty, &hir_id));
debug_assert!(!instantiated_ty.has_escaping_bound_vars());
@ -444,7 +445,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// figures out the concrete type with `U`, but the stored type is with `T`.
let definition_ty = self.fcx.infer_opaque_definition_from_instantiation(
def_id,
opaque_defn,
opaque_defn.substs,
instantiated_ty,
span,
);

View File

@ -1,5 +1,3 @@
// ignore-tidy-filelength
//! "Collection" is the process of determining the type and other external
//! details of each item in Rust. Collection is specifically concerned
//! with *inter-procedural* things -- for example, for a function
@ -27,18 +25,16 @@ use rustc::hir::map::Map;
use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc::mir::mono::Linkage;
use rustc::session::parse::feature_err;
use rustc::traits;
use rustc::ty::query::Providers;
use rustc::ty::subst::GenericArgKind;
use rustc::ty::subst::{InternalSubsts, Subst};
use rustc::ty::util::Discr;
use rustc::ty::util::IntTypeExt;
use rustc::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt, WithConstness};
use rustc::ty::{ReprOptions, ToPredicate};
use rustc::ty::{self, AdtKind, Const, ToPolyTraitRef, Ty, TyCtxt};
use rustc::ty::{ReprOptions, ToPredicate, WithConstness};
use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, StashKey};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@ -50,6 +46,8 @@ use rustc_target::spec::abi;
use syntax::ast;
use syntax::ast::{Ident, MetaItemKind};
mod type_of;
struct OnlySelfBounds(bool);
///////////////////////////////////////////////////////////////////////////
@ -64,7 +62,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: DefId) {
pub fn provide(providers: &mut Providers<'_>) {
*providers = Providers {
type_of,
type_of: type_of::type_of,
generics_of,
predicates_of,
predicates_defined_on,
@ -1329,601 +1327,6 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics {
})
}
fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) {
struct_span_err!(
tcx.sess,
span,
E0202,
"associated types are not yet supported in inherent impls (see #8995)"
)
.emit();
}
fn infer_placeholder_type(
tcx: TyCtxt<'_>,
def_id: DefId,
body_id: hir::BodyId,
span: Span,
item_ident: Ident,
) -> Ty<'_> {
let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id);
// If this came from a free `const` or `static mut?` item,
// then the user may have written e.g. `const A = 42;`.
// In this case, the parser has stashed a diagnostic for
// us to improve in typeck so we do that now.
match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
Some(mut err) => {
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
// We are typeck and have the real type, so remove that and suggest the actual type.
err.suggestions.clear();
err.span_suggestion(
span,
"provide a type for the item",
format!("{}: {}", item_ident, ty),
Applicability::MachineApplicable,
)
.emit();
}
None => {
let mut diag = bad_placeholder_type(tcx, vec![span]);
if ty != tcx.types.err {
diag.span_suggestion(
span,
"replace `_` with the correct type",
ty.to_string(),
Applicability::MaybeIncorrect,
);
}
diag.emit();
}
}
ty
}
fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
use rustc_hir::*;
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let icx = ItemCtxt::new(tcx, def_id);
match tcx.hir().get(hir_id) {
Node::TraitItem(item) => match item.kind {
TraitItemKind::Method(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
TraitItemKind::Const(ref ty, body_id) => body_id
.and_then(|body_id| {
if is_suggestable_infer_ty(ty) {
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
} else {
None
}
})
.unwrap_or_else(|| icx.to_ty(ty)),
TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
TraitItemKind::Type(_, None) => {
span_bug!(item.span, "associated type missing default");
}
},
Node::ImplItem(item) => match item.kind {
ImplItemKind::Method(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
ImplItemKind::Const(ref ty, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else {
icx.to_ty(ty)
}
}
ImplItemKind::OpaqueTy(_) => {
if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() {
report_assoc_ty_on_inherent_impl(tcx, item.span);
}
find_opaque_ty_constraints(tcx, def_id)
}
ImplItemKind::TyAlias(ref ty) => {
if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() {
report_assoc_ty_on_inherent_impl(tcx, item.span);
}
icx.to_ty(ty)
}
},
Node::Item(item) => {
match item.kind {
ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else {
icx.to_ty(ty)
}
}
ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => {
icx.to_ty(self_ty)
}
ItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
let def = tcx.adt_def(def_id);
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_adt(def, substs)
}
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => {
find_opaque_ty_constraints(tcx, def_id)
}
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
tcx.typeck_tables_of(owner)
.concrete_opaque_types
.get(&def_id)
.map(|opaque| opaque.concrete_type)
.unwrap_or_else(|| {
// This can occur if some error in the
// owner fn prevented us from populating
// the `concrete_opaque_types` table.
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"owner {:?} has no opaque type for {:?} in its tables",
owner, def_id,
),
);
tcx.types.err
})
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod(..)
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
span_bug!(
item.span,
"compute_type_of_item: unexpected item type: {:?}",
item.kind
);
}
}
}
Node::ForeignItem(foreign_item) => match foreign_item.kind {
ForeignItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
ForeignItemKind::Static(ref t, _) => icx.to_ty(t),
ForeignItemKind::Type => tcx.mk_foreign(def_id),
},
Node::Ctor(&ref def) | Node::Variant(hir::Variant { data: ref def, .. }) => match *def {
VariantData::Unit(..) | VariantData::Struct(..) => {
tcx.type_of(tcx.hir().get_parent_did(hir_id))
}
VariantData::Tuple(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
},
Node::Field(field) => icx.to_ty(&field.ty),
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(.., gen), .. }) => {
if gen.is_some() {
return tcx.typeck_tables_of(def_id).node_type(hir_id);
}
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_closure(def_id, substs)
}
Node::AnonConst(_) => {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
match parent_node {
Node::Ty(&hir::Ty { kind: hir::TyKind::Array(_, ref constant), .. })
| Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref constant), .. })
| Node::Expr(&hir::Expr { kind: ExprKind::Repeat(_, ref constant), .. })
if constant.hir_id == hir_id =>
{
tcx.types.usize
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir().get_parent_did(hir_id)).repr.discr_type().to_ty(tcx)
}
Node::Ty(&hir::Ty { kind: hir::TyKind::Path(_), .. })
| Node::Expr(&hir::Expr { kind: ExprKind::Struct(..), .. })
| Node::Expr(&hir::Expr { kind: ExprKind::Path(_), .. })
| Node::TraitRef(..) => {
let path = match parent_node {
Node::Ty(&hir::Ty {
kind: hir::TyKind::Path(QPath::Resolved(_, ref path)),
..
})
| Node::Expr(&hir::Expr {
kind: ExprKind::Path(QPath::Resolved(_, ref path)),
..
}) => Some(&**path),
Node::Expr(&hir::Expr { kind: ExprKind::Struct(ref path, ..), .. }) => {
if let QPath::Resolved(_, ref path) = **path {
Some(&**path)
} else {
None
}
}
Node::TraitRef(&hir::TraitRef { ref path, .. }) => Some(&**path),
_ => None,
};
if let Some(path) = path {
let arg_index = path
.segments
.iter()
.filter_map(|seg| seg.args.as_ref())
.map(|generic_args| generic_args.args.as_ref())
.find_map(|args| {
args.iter()
.filter(|arg| arg.is_const())
.enumerate()
.filter(|(_, arg)| arg.id() == hir_id)
.map(|(index, _)| index)
.next()
})
.unwrap_or_else(|| {
bug!("no arg matching AnonConst in path");
});
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
let generics = match path.res {
Res::Def(DefKind::Ctor(..), def_id) => {
tcx.generics_of(tcx.parent(def_id).unwrap())
}
Res::Def(_, def_id) => tcx.generics_of(def_id),
Res::Err => return tcx.types.err,
res => {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("unexpected const parent path def {:?}", res,),
);
return tcx.types.err;
}
};
generics
.params
.iter()
.filter(|param| {
if let ty::GenericParamDefKind::Const = param.kind {
true
} else {
false
}
})
.nth(arg_index)
.map(|param| tcx.type_of(param.def_id))
// This is no generic parameter associated with the arg. This is
// probably from an extra arg where one is not needed.
.unwrap_or(tcx.types.err)
} else {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("unexpected const parent path {:?}", parent_node,),
);
return tcx.types.err;
}
}
x => {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("unexpected const parent in type_of_def_id(): {:?}", x),
);
tcx.types.err
}
}
}
Node::GenericParam(param) => match &param.kind {
hir::GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
hir::GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
if !tcx.features().const_compare_raw_pointers {
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
feature_err(
&tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
hir_ty.span,
&format!(
"using {} as const generic parameters is unstable",
unsupported_type
),
)
.emit();
};
}
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
{
struct_span_err!(
tcx.sess,
hir_ty.span,
E0741,
"the types of const generic parameters must derive `PartialEq` and `Eq`",
)
.span_label(
hir_ty.span,
format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
)
.emit();
}
ty
}
x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
},
x => {
bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
}
}
}
fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
use rustc_hir::{ImplItem, Item, TraitItem};
debug!("find_opaque_ty_constraints({:?})", def_id);
struct ConstraintLocator<'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
// (first found type span, actual type, mapping from the opaque type's generic
// parameters to the concrete type's generic parameters)
//
// The mapping is an index for each use site of a generic parameter in the concrete type
//
// The indices index into the generic parameters on the opaque type.
found: Option<(Span, Ty<'tcx>, Vec<usize>)>,
}
impl ConstraintLocator<'tcx> {
fn check(&mut self, def_id: DefId) {
// Don't try to check items that cannot possibly constrain the type.
if !self.tcx.has_typeck_tables(def_id) {
debug!(
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables",
self.def_id, def_id,
);
return;
}
let ty = self.tcx.typeck_tables_of(def_id).concrete_opaque_types.get(&self.def_id);
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
debug!(
"find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
self.def_id, def_id, ty,
);
// FIXME(oli-obk): trace the actual span from inference to improve errors.
let span = self.tcx.def_span(def_id);
// used to quickly look up the position of a generic parameter
let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
// Skipping binder is ok, since we only use this to find generic parameters and
// their positions.
for (idx, subst) in substs.iter().enumerate() {
if let GenericArgKind::Type(ty) = subst.unpack() {
if let ty::Param(p) = ty.kind {
if index_map.insert(p, idx).is_some() {
// There was already an entry for `p`, meaning a generic parameter
// was used twice.
self.tcx.sess.span_err(
span,
&format!(
"defining opaque type use restricts opaque \
type by using the generic parameter `{}` twice",
p,
),
);
return;
}
} else {
self.tcx.sess.delay_span_bug(
span,
&format!(
"non-defining opaque ty use in defining scope: {:?}, {:?}",
concrete_type, substs,
),
);
}
}
}
// Compute the index within the opaque type for each generic parameter used in
// the concrete type.
let indices = concrete_type
.subst(self.tcx, substs)
.walk()
.filter_map(|t| match &t.kind {
ty::Param(p) => Some(*index_map.get(p).unwrap()),
_ => None,
})
.collect();
let is_param = |ty: Ty<'_>| match ty.kind {
ty::Param(_) => true,
_ => false,
};
let bad_substs: Vec<_> = substs
.iter()
.enumerate()
.filter_map(|(i, k)| {
if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None }
})
.filter(|(_, ty)| !is_param(ty))
.collect();
if !bad_substs.is_empty() {
let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id);
for (i, bad_subst) in bad_substs {
self.tcx.sess.span_err(
span,
&format!(
"defining opaque type use does not fully define opaque type: \
generic parameter `{}` is specified as concrete type `{}`",
identity_substs.type_at(i),
bad_subst
),
);
}
} else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
let mut ty = concrete_type.walk().fuse();
let mut p_ty = prev_ty.walk().fuse();
let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) {
// Type parameters are equal to any other type parameter for the purpose of
// concrete type equality, as it is possible to obtain the same type just
// by passing matching parameters to a function.
(ty::Param(_), ty::Param(_)) => true,
_ => t == p,
});
if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
debug!("find_opaque_ty_constraints: span={:?}", span);
// Found different concrete types for the opaque type.
let mut err = self.tcx.sess.struct_span_err(
span,
"concrete type differs from previous defining opaque type use",
);
err.span_label(
span,
format!("expected `{}`, got `{}`", prev_ty, concrete_type),
);
err.span_note(prev_span, "previous use here");
err.emit();
} else if indices != *prev_indices {
// Found "same" concrete types, but the generic parameter order differs.
let mut err = self.tcx.sess.struct_span_err(
span,
"concrete type's generic parameters differ from previous defining use",
);
use std::fmt::Write;
let mut s = String::new();
write!(s, "expected [").unwrap();
let list = |s: &mut String, indices: &Vec<usize>| {
let mut indices = indices.iter().cloned();
if let Some(first) = indices.next() {
write!(s, "`{}`", substs[first]).unwrap();
for i in indices {
write!(s, ", `{}`", substs[i]).unwrap();
}
}
};
list(&mut s, prev_indices);
write!(s, "], got [").unwrap();
list(&mut s, &indices);
write!(s, "]").unwrap();
err.span_label(span, s);
err.span_note(prev_span, "previous use here");
err.emit();
}
} else {
self.found = Some((span, concrete_type, indices));
}
} else {
debug!(
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
self.def_id, def_id,
);
}
}
}
impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
intravisit::NestedVisitorMap::All(&self.tcx.hir())
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
let def_id = self.tcx.hir().local_def_id(it.hir_id);
// The opaque type itself or its children are not within its reveal scope.
if def_id != self.def_id {
self.check(def_id);
intravisit::walk_item(self, it);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
let def_id = self.tcx.hir().local_def_id(it.hir_id);
// The opaque type itself or its children are not within its reveal scope.
if def_id != self.def_id {
self.check(def_id);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
let def_id = self.tcx.hir().local_def_id(it.hir_id);
self.check(def_id);
intravisit::walk_trait_item(self, it);
}
}
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let scope = tcx.hir().get_defining_scope(hir_id);
let mut locator = ConstraintLocator { def_id, tcx, found: None };
debug!("find_opaque_ty_constraints: scope={:?}", scope);
if scope == hir::CRATE_HIR_ID {
intravisit::walk_crate(&mut locator, tcx.hir().krate());
} else {
debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
match tcx.hir().get(scope) {
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
// This allows our visitor to process the defining item itself, causing
// it to pick up any 'sibling' defining uses.
//
// For example, this code:
// ```
// fn foo() {
// type Blah = impl Debug;
// let my_closure = || -> Blah { true };
// }
// ```
//
// requires us to explicitly process `foo()` in order
// to notice the defining usage of `Blah`.
Node::Item(ref it) => locator.visit_item(it),
Node::ImplItem(ref it) => locator.visit_impl_item(it),
Node::TraitItem(ref it) => locator.visit_trait_item(it),
other => bug!("{:?} is not a valid scope for an opaque type item", other),
}
}
match locator.found {
Some((_, ty, _)) => ty,
None => {
let span = tcx.def_span(def_id);
tcx.sess.span_err(span, "could not find defining uses");
tcx.types.err
}
}
}
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
generic_args
.iter()

View File

@ -0,0 +1,661 @@
use rustc::hir::map::Map;
use rustc::session::parse::feature_err;
use rustc::traits;
use rustc::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc::ty::util::IntTypeExt;
use rustc::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Applicability, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
use super::ItemCtxt;
use super::{bad_placeholder_type, is_suggestable_infer_ty};
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
use rustc_hir::*;
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let icx = ItemCtxt::new(tcx, def_id);
match tcx.hir().get(hir_id) {
Node::TraitItem(item) => match item.kind {
TraitItemKind::Method(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
TraitItemKind::Const(ref ty, body_id) => body_id
.and_then(|body_id| {
if is_suggestable_infer_ty(ty) {
Some(infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident))
} else {
None
}
})
.unwrap_or_else(|| icx.to_ty(ty)),
TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
TraitItemKind::Type(_, None) => {
span_bug!(item.span, "associated type missing default");
}
},
Node::ImplItem(item) => match item.kind {
ImplItemKind::Method(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
ImplItemKind::Const(ref ty, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else {
icx.to_ty(ty)
}
}
ImplItemKind::OpaqueTy(_) => {
if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() {
report_assoc_ty_on_inherent_impl(tcx, item.span);
}
find_opaque_ty_constraints(tcx, def_id)
}
ImplItemKind::TyAlias(ref ty) => {
if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id)).is_none() {
report_assoc_ty_on_inherent_impl(tcx, item.span);
}
icx.to_ty(ty)
}
},
Node::Item(item) => {
match item.kind {
ItemKind::Static(ref ty, .., body_id) | ItemKind::Const(ref ty, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident)
} else {
icx.to_ty(ty)
}
}
ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => {
icx.to_ty(self_ty)
}
ItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
let def = tcx.adt_def(def_id);
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_adt(def, substs)
}
ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => {
find_opaque_ty_constraints(tcx, def_id)
}
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), origin, .. }) => {
let concrete_types = match origin {
OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => {
&tcx.mir_borrowck(owner).concrete_opaque_types
}
OpaqueTyOrigin::Misc => {
// We shouldn't leak borrowck results through impl trait in bindings.
// For example, we shouldn't be able to tell if `x` in
// `let x: impl Sized + 'a = &()` has type `&'static ()` or `&'a ()`.
&tcx.typeck_tables_of(owner).concrete_opaque_types
}
OpaqueTyOrigin::TypeAlias => {
span_bug!(item.span, "Type alias impl trait shouldn't have an owner")
}
};
let concrete_ty = concrete_types
.get(&def_id)
.map(|opaque| opaque.concrete_type)
.unwrap_or_else(|| {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!(
"owner {:?} has no opaque type for {:?} in its tables",
owner, def_id,
),
);
if tcx.typeck_tables_of(owner).tainted_by_errors {
// Some error in the
// owner fn prevented us from populating
// the `concrete_opaque_types` table.
tcx.types.err
} else {
// We failed to resolve the opaque type or it
// resolves to itself. Return the non-revealed
// type, which should result in E0720.
tcx.mk_opaque(
def_id,
InternalSubsts::identity_for_item(tcx, def_id),
)
}
});
debug!("concrete_ty = {:?}", concrete_ty);
if concrete_ty.has_erased_regions() {
// FIXME(impl_trait_in_bindings) Handle this case.
tcx.sess.span_fatal(
item.span,
"lifetimes in impl Trait types in bindings are not currently supported",
);
}
concrete_ty
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod(..)
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
span_bug!(
item.span,
"compute_type_of_item: unexpected item type: {:?}",
item.kind
);
}
}
}
Node::ForeignItem(foreign_item) => match foreign_item.kind {
ForeignItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
ForeignItemKind::Static(ref t, _) => icx.to_ty(t),
ForeignItemKind::Type => tcx.mk_foreign(def_id),
},
Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
VariantData::Unit(..) | VariantData::Struct(..) => {
tcx.type_of(tcx.hir().get_parent_did(hir_id))
}
VariantData::Tuple(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_fn_def(def_id, substs)
}
},
Node::Field(field) => icx.to_ty(&field.ty),
Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
if gen.is_some() {
return tcx.typeck_tables_of(def_id).node_type(hir_id);
}
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_closure(def_id, substs)
}
Node::AnonConst(_) => {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
match parent_node {
Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
| Node::Ty(&Ty { kind: TyKind::Typeof(ref constant), .. })
| Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
if constant.hir_id == hir_id =>
{
tcx.types.usize
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
tcx.adt_def(tcx.hir().get_parent_did(hir_id)).repr.discr_type().to_ty(tcx)
}
Node::Ty(&Ty { kind: TyKind::Path(_), .. })
| Node::Expr(&Expr { kind: ExprKind::Struct(..), .. })
| Node::Expr(&Expr { kind: ExprKind::Path(_), .. })
| Node::TraitRef(..) => {
let path = match parent_node {
Node::Ty(&Ty {
kind: TyKind::Path(QPath::Resolved(_, ref path)), ..
})
| Node::Expr(&Expr {
kind: ExprKind::Path(QPath::Resolved(_, ref path)),
..
}) => Some(&**path),
Node::Expr(&Expr { kind: ExprKind::Struct(ref path, ..), .. }) => {
if let QPath::Resolved(_, ref path) = **path {
Some(&**path)
} else {
None
}
}
Node::TraitRef(&TraitRef { ref path, .. }) => Some(&**path),
_ => None,
};
if let Some(path) = path {
let arg_index = path
.segments
.iter()
.filter_map(|seg| seg.args.as_ref())
.map(|generic_args| generic_args.args.as_ref())
.find_map(|args| {
args.iter()
.filter(|arg| arg.is_const())
.enumerate()
.filter(|(_, arg)| arg.id() == hir_id)
.map(|(index, _)| index)
.next()
})
.unwrap_or_else(|| {
bug!("no arg matching AnonConst in path");
});
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
let generics = match path.res {
Res::Def(DefKind::Ctor(..), def_id) => {
tcx.generics_of(tcx.parent(def_id).unwrap())
}
Res::Def(_, def_id) => tcx.generics_of(def_id),
Res::Err => return tcx.types.err,
res => {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("unexpected const parent path def {:?}", res,),
);
return tcx.types.err;
}
};
generics
.params
.iter()
.filter(|param| {
if let ty::GenericParamDefKind::Const = param.kind {
true
} else {
false
}
})
.nth(arg_index)
.map(|param| tcx.type_of(param.def_id))
// This is no generic parameter associated with the arg. This is
// probably from an extra arg where one is not needed.
.unwrap_or(tcx.types.err)
} else {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("unexpected const parent path {:?}", parent_node,),
);
return tcx.types.err;
}
}
x => {
tcx.sess.delay_span_bug(
DUMMY_SP,
&format!("unexpected const parent in type_of_def_id(): {:?}", x),
);
tcx.types.err
}
}
}
Node::GenericParam(param) => match &param.kind {
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
if !tcx.features().const_compare_raw_pointers {
let err = match ty.peel_refs().kind {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
_ => None,
};
if let Some(unsupported_type) = err {
feature_err(
&tcx.sess.parse_sess,
sym::const_compare_raw_pointers,
hir_ty.span,
&format!(
"using {} as const generic parameters is unstable",
unsupported_type
),
)
.emit();
};
}
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
{
struct_span_err!(
tcx.sess,
hir_ty.span,
E0741,
"the types of const generic parameters must derive `PartialEq` and `Eq`",
)
.span_label(
hir_ty.span,
format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
)
.emit();
}
ty
}
x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
},
x => {
bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
}
}
}
fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
use rustc_hir::{Expr, ImplItem, Item, TraitItem};
debug!("find_opaque_ty_constraints({:?})", def_id);
struct ConstraintLocator<'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
// (first found type span, actual type, mapping from the opaque type's generic
// parameters to the concrete type's generic parameters)
//
// The mapping is an index for each use site of a generic parameter in the concrete type
//
// The indices index into the generic parameters on the opaque type.
found: Option<(Span, Ty<'tcx>, Vec<usize>)>,
}
impl ConstraintLocator<'_> {
fn check(&mut self, def_id: DefId) {
// Don't try to check items that cannot possibly constrain the type.
if !self.tcx.has_typeck_tables(def_id) {
debug!(
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`: no tables",
self.def_id, def_id,
);
return;
}
// Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to.
if !self.tcx.typeck_tables_of(def_id).concrete_opaque_types.contains_key(&self.def_id) {
debug!(
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
self.def_id, def_id,
);
return;
}
// Use borrowck to get the type with unerased regions.
let ty = self.tcx.mir_borrowck(def_id).concrete_opaque_types.get(&self.def_id);
if let Some(ty::ResolvedOpaqueTy { concrete_type, substs }) = ty {
debug!(
"find_opaque_ty_constraints: found constraint for `{:?}` at `{:?}`: {:?}",
self.def_id, def_id, ty,
);
// FIXME(oli-obk): trace the actual span from inference to improve errors.
let span = self.tcx.def_span(def_id);
// used to quickly look up the position of a generic parameter
let mut index_map: FxHashMap<ty::ParamTy, usize> = FxHashMap::default();
// Skipping binder is ok, since we only use this to find generic parameters and
// their positions.
for (idx, subst) in substs.iter().enumerate() {
if let GenericArgKind::Type(ty) = subst.unpack() {
if let ty::Param(p) = ty.kind {
if index_map.insert(p, idx).is_some() {
// There was already an entry for `p`, meaning a generic parameter
// was used twice.
self.tcx.sess.span_err(
span,
&format!(
"defining opaque type use restricts opaque \
type by using the generic parameter `{}` twice",
p,
),
);
return;
}
} else {
self.tcx.sess.delay_span_bug(
span,
&format!(
"non-defining opaque ty use in defining scope: {:?}, {:?}",
concrete_type, substs,
),
);
}
}
}
// Compute the index within the opaque type for each generic parameter used in
// the concrete type.
let indices = concrete_type
.subst(self.tcx, substs)
.walk()
.filter_map(|t| match &t.kind {
ty::Param(p) => Some(*index_map.get(p).unwrap()),
_ => None,
})
.collect();
let is_param = |ty: Ty<'_>| match ty.kind {
ty::Param(_) => true,
_ => false,
};
let bad_substs: Vec<_> = substs
.iter()
.enumerate()
.filter_map(|(i, k)| {
if let GenericArgKind::Type(ty) = k.unpack() { Some((i, ty)) } else { None }
})
.filter(|(_, ty)| !is_param(ty))
.collect();
if !bad_substs.is_empty() {
let identity_substs = InternalSubsts::identity_for_item(self.tcx, self.def_id);
for (i, bad_subst) in bad_substs {
self.tcx.sess.span_err(
span,
&format!(
"defining opaque type use does not fully define opaque type: \
generic parameter `{}` is specified as concrete type `{}`",
identity_substs.type_at(i),
bad_subst
),
);
}
} else if let Some((prev_span, prev_ty, ref prev_indices)) = self.found {
let mut ty = concrete_type.walk().fuse();
let mut p_ty = prev_ty.walk().fuse();
let iter_eq = (&mut ty).zip(&mut p_ty).all(|(t, p)| match (&t.kind, &p.kind) {
// Type parameters are equal to any other type parameter for the purpose of
// concrete type equality, as it is possible to obtain the same type just
// by passing matching parameters to a function.
(ty::Param(_), ty::Param(_)) => true,
_ => t == p,
});
if !iter_eq || ty.next().is_some() || p_ty.next().is_some() {
debug!("find_opaque_ty_constraints: span={:?}", span);
// Found different concrete types for the opaque type.
let mut err = self.tcx.sess.struct_span_err(
span,
"concrete type differs from previous defining opaque type use",
);
err.span_label(
span,
format!("expected `{}`, got `{}`", prev_ty, concrete_type),
);
err.span_note(prev_span, "previous use here");
err.emit();
} else if indices != *prev_indices {
// Found "same" concrete types, but the generic parameter order differs.
let mut err = self.tcx.sess.struct_span_err(
span,
"concrete type's generic parameters differ from previous defining use",
);
use std::fmt::Write;
let mut s = String::new();
write!(s, "expected [").unwrap();
let list = |s: &mut String, indices: &Vec<usize>| {
let mut indices = indices.iter().cloned();
if let Some(first) = indices.next() {
write!(s, "`{}`", substs[first]).unwrap();
for i in indices {
write!(s, ", `{}`", substs[i]).unwrap();
}
}
};
list(&mut s, prev_indices);
write!(s, "], got [").unwrap();
list(&mut s, &indices);
write!(s, "]").unwrap();
err.span_label(span, s);
err.span_note(prev_span, "previous use here");
err.emit();
}
} else {
self.found = Some((span, concrete_type, indices));
}
} else {
debug!(
"find_opaque_ty_constraints: no constraint for `{:?}` at `{:?}`",
self.def_id, def_id,
);
}
}
}
impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<'_, Self::Map> {
intravisit::NestedVisitorMap::All(&self.tcx.hir())
}
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
if let hir::ExprKind::Closure(..) = ex.kind {
let def_id = self.tcx.hir().local_def_id(ex.hir_id);
self.check(def_id);
}
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
let def_id = self.tcx.hir().local_def_id(it.hir_id);
// The opaque type itself or its children are not within its reveal scope.
if def_id != self.def_id {
self.check(def_id);
intravisit::walk_item(self, it);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
let def_id = self.tcx.hir().local_def_id(it.hir_id);
// The opaque type itself or its children are not within its reveal scope.
if def_id != self.def_id {
self.check(def_id);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
debug!("find_existential_constraints: visiting {:?}", it);
let def_id = self.tcx.hir().local_def_id(it.hir_id);
self.check(def_id);
intravisit::walk_trait_item(self, it);
}
}
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
let scope = tcx.hir().get_defining_scope(hir_id);
let mut locator = ConstraintLocator { def_id, tcx, found: None };
debug!("find_opaque_ty_constraints: scope={:?}", scope);
if scope == hir::CRATE_HIR_ID {
intravisit::walk_crate(&mut locator, tcx.hir().krate());
} else {
debug!("find_opaque_ty_constraints: scope={:?}", tcx.hir().get(scope));
match tcx.hir().get(scope) {
// We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
// This allows our visitor to process the defining item itself, causing
// it to pick up any 'sibling' defining uses.
//
// For example, this code:
// ```
// fn foo() {
// type Blah = impl Debug;
// let my_closure = || -> Blah { true };
// }
// ```
//
// requires us to explicitly process `foo()` in order
// to notice the defining usage of `Blah`.
Node::Item(ref it) => locator.visit_item(it),
Node::ImplItem(ref it) => locator.visit_impl_item(it),
Node::TraitItem(ref it) => locator.visit_trait_item(it),
other => bug!("{:?} is not a valid scope for an opaque type item", other),
}
}
match locator.found {
Some((_, ty, _)) => ty,
None => {
let span = tcx.def_span(def_id);
tcx.sess.span_err(span, "could not find defining uses");
tcx.types.err
}
}
}
fn infer_placeholder_type(
tcx: TyCtxt<'_>,
def_id: DefId,
body_id: hir::BodyId,
span: Span,
item_ident: Ident,
) -> Ty<'_> {
let ty = tcx.diagnostic_only_typeck_tables_of(def_id).node_type(body_id.hir_id);
// If this came from a free `const` or `static mut?` item,
// then the user may have written e.g. `const A = 42;`.
// In this case, the parser has stashed a diagnostic for
// us to improve in typeck so we do that now.
match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
Some(mut err) => {
// The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
// We are typeck and have the real type, so remove that and suggest the actual type.
err.suggestions.clear();
err.span_suggestion(
span,
"provide a type for the item",
format!("{}: {}", item_ident, ty),
Applicability::MachineApplicable,
)
.emit();
}
None => {
let mut diag = bad_placeholder_type(tcx, vec![span]);
if ty != tcx.types.err {
diag.span_suggestion(
span,
"replace `_` with the correct type",
ty.to_string(),
Applicability::MaybeIncorrect,
);
}
diag.emit();
}
}
ty
}
fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) {
struct_span_err!(
tcx.sess,
span,
E0202,
"associated types are not yet supported in inherent impls (see #8995)"
)
.emit();
}

View File

@ -120,11 +120,26 @@ fn enforce_impl_params_are_constrained(
let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs
.iter()
.map(|item_ref| tcx.hir().local_def_id(item_ref.id.hir_id))
.filter(|&def_id| {
.flat_map(|def_id| {
let item = tcx.associated_item(def_id);
item.kind == ty::AssocKind::Type && item.defaultness.has_value()
match item.kind {
ty::AssocKind::Type => {
if item.defaultness.has_value() {
cgp::parameters_for(&tcx.type_of(def_id), true)
} else {
Vec::new()
}
}
ty::AssocKind::OpaqueTy => {
// We don't know which lifetimes appear in the actual
// opaque type, so use all of the lifetimes that appear
// in the type's predicates.
let predicates = tcx.predicates_of(def_id).instantiate_identity(tcx);
cgp::parameters_for(&predicates, true)
}
ty::AssocKind::Method | ty::AssocKind::Const => Vec::new(),
}
})
.flat_map(|def_id| cgp::parameters_for(&tcx.type_of(def_id), true))
.collect();
for param in &impl_generics.params {

View File

@ -16,9 +16,10 @@ pub use core::future::*;
///
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
// This is `const` to avoid extra errors after we recover from `const async fn`
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
pub const fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
GenFuture(x)
}

View File

@ -1,11 +1,3 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/issue-63388-1.rs:12:10
|
LL | ) -> &dyn Foo
| ^^^^^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#22r
error: lifetime may not live long enough
--> $DIR/issue-63388-1.rs:13:5
|
@ -19,6 +11,5 @@ LL | | foo
LL | | }
| |_____^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
error: aborting due to 2 previous errors
error: aborting due to previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -3,3 +3,4 @@
pub const async fn x() {}
//~^ ERROR functions cannot be both `const` and `async`
//~| ERROR `impl Trait` in const fn is unstable

View File

@ -7,5 +7,15 @@ LL | pub const async fn x() {}
| | `async` because of this
| `const` because of this
error: aborting due to previous error
error[E0723]: `impl Trait` in const fn is unstable
--> $DIR/no-const-async.rs:4:24
|
LL | pub const async fn x() {}
| ^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0723`.

View File

@ -0,0 +1,14 @@
#![feature(unboxed_closures)]
// Tests that we can't assign to or mutably borrow upvars from `Fn`
// closures (issue #17780)
fn main() {}
fn bar() -> impl Fn() -> usize {
let mut x = 0;
move || {
x += 1; //~ ERROR cannot assign
x
}
}

View File

@ -0,0 +1,16 @@
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation-impl-trait.rs:11:9
|
LL | fn bar() -> impl Fn() -> usize {
| --- ------------------ change this to return `FnMut` instead of `Fn`
LL | let mut x = 0;
LL | / move || {
LL | | x += 1;
| | ^^^^^^ cannot assign
LL | | x
LL | | }
| |_____- in this closure
error: aborting due to previous error
For more information about this error, try `rustc --explain E0594`.

View File

@ -3,10 +3,16 @@
// Tests that we can't assign to or mutably borrow upvars from `Fn`
// closures (issue #17780)
fn set(x: &mut usize) { *x = 5; }
fn set(x: &mut usize) {
*x = 5;
}
fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
fn to_fn<A, F: Fn<A>>(f: F) -> F {
f
}
fn to_fn_mut<A, F: FnMut<A>>(f: F) -> F {
f
}
fn main() {
// By-ref captures
@ -33,7 +39,11 @@ fn main() {
let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
let mut z = 0;
let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
let _h = to_fn_mut(move || {
set(&mut z);
to_fn(move || z = 42);
//~^ ERROR cannot assign
});
}
}
@ -44,11 +54,3 @@ fn foo() -> Box<dyn Fn() -> usize> {
x
})
}
fn bar() -> impl Fn() -> usize {
let mut x = 0;
move || {
x += 1; //~ ERROR cannot assign
x
}
}

View File

@ -1,8 +1,8 @@
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:15:27
--> $DIR/borrow-immutable-upvar-mutation.rs:21:27
|
LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
| - change this to accept `FnMut` instead of `Fn`
LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
| - change this to accept `FnMut` instead of `Fn`
...
LL | let _f = to_fn(|| x = 42);
| ----- ^^^^^^ cannot assign
@ -10,10 +10,10 @@ LL | let _f = to_fn(|| x = 42);
| expects `Fn` instead of `FnMut`
error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:18:31
--> $DIR/borrow-immutable-upvar-mutation.rs:24:31
|
LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
| - change this to accept `FnMut` instead of `Fn`
LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
| - change this to accept `FnMut` instead of `Fn`
...
LL | let _g = to_fn(|| set(&mut y));
| ----- ^^^^^^ cannot borrow as mutable
@ -21,10 +21,10 @@ LL | let _g = to_fn(|| set(&mut y));
| expects `Fn` instead of `FnMut`
error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:23:22
--> $DIR/borrow-immutable-upvar-mutation.rs:29:22
|
LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
| - change this to accept `FnMut` instead of `Fn`
LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
| - change this to accept `FnMut` instead of `Fn`
...
LL | to_fn(|| z = 42);
| ----- ^^^^^^ cannot assign
@ -32,10 +32,10 @@ LL | to_fn(|| z = 42);
| expects `Fn` instead of `FnMut`
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:30:32
--> $DIR/borrow-immutable-upvar-mutation.rs:36:32
|
LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
| - change this to accept `FnMut` instead of `Fn`
LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
| - change this to accept `FnMut` instead of `Fn`
...
LL | let _f = to_fn(move || x = 42);
| ----- ^^^^^^ cannot assign
@ -43,10 +43,10 @@ LL | let _f = to_fn(move || x = 42);
| expects `Fn` instead of `FnMut`
error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:33:36
--> $DIR/borrow-immutable-upvar-mutation.rs:39:36
|
LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
| - change this to accept `FnMut` instead of `Fn`
LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
| - change this to accept `FnMut` instead of `Fn`
...
LL | let _g = to_fn(move || set(&mut y));
| ----- ^^^^^^ cannot borrow as mutable
@ -54,18 +54,18 @@ LL | let _g = to_fn(move || set(&mut y));
| expects `Fn` instead of `FnMut`
error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:36:65
--> $DIR/borrow-immutable-upvar-mutation.rs:44:27
|
LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
| - change this to accept `FnMut` instead of `Fn`
LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
| - change this to accept `FnMut` instead of `Fn`
...
LL | let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); });
| ----- ^^^^^^ cannot assign
| |
| expects `Fn` instead of `FnMut`
LL | to_fn(move || z = 42);
| ----- ^^^^^^ cannot assign
| |
| expects `Fn` instead of `FnMut`
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:43:9
--> $DIR/borrow-immutable-upvar-mutation.rs:53:9
|
LL | fn foo() -> Box<dyn Fn() -> usize> {
| --- ---------------------- change this to return `FnMut` instead of `Fn`
@ -78,20 +78,7 @@ LL | | x
LL | | })
| |_____- in this closure
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:51:9
|
LL | fn bar() -> impl Fn() -> usize {
| --- ------------------ change this to return `FnMut` instead of `Fn`
LL | let mut x = 0;
LL | / move || {
LL | | x += 1;
| | ^^^^^^ cannot assign
LL | | x
LL | | }
| |_____- in this closure
error: aborting due to 8 previous errors
error: aborting due to 7 previous errors
Some errors have detailed explanations: E0594, E0596.
For more information about an error, try `rustc --explain E0594`.

View File

@ -123,12 +123,9 @@ impl<T: Sync + Sized> Foo<T> {
}
struct AlanTuring<T>(T);
const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
//~^ ERROR `impl Trait` in const fn is unstable
const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
//~^ ERROR trait bounds other than `Sized`
const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
//~^ ERROR trait bounds other than `Sized`

View File

@ -214,17 +214,8 @@ LL | impl<T: Sync + Sized> Foo<T> {
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn.rs:126:24
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:128:34
--> $DIR/min_const_fn.rs:126:34
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
@ -233,7 +224,7 @@ LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:130:22
--> $DIR/min_const_fn.rs:128:22
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {}
| ^^^^^^^^^^^^^^^^^^^^
@ -241,17 +232,8 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {}
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn.rs:131:23
|
LL | const fn no_rpit() -> impl std::fmt::Debug {}
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:132:23
--> $DIR/min_const_fn.rs:129:23
|
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
| ^^
@ -260,7 +242,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:133:32
--> $DIR/min_const_fn.rs:130:32
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -269,7 +251,7 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
--> $DIR/min_const_fn.rs:138:41
--> $DIR/min_const_fn.rs:135:41
|
LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -278,7 +260,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: function pointers in const fn are unstable
--> $DIR/min_const_fn.rs:141:21
--> $DIR/min_const_fn.rs:138:21
|
LL | const fn no_fn_ptrs(_x: fn()) {}
| ^^
@ -287,7 +269,7 @@ LL | const fn no_fn_ptrs(_x: fn()) {}
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: function pointers in const fn are unstable
--> $DIR/min_const_fn.rs:143:27
--> $DIR/min_const_fn.rs:140:27
|
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^
@ -295,7 +277,7 @@ LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error: aborting due to 34 previous errors
error: aborting due to 32 previous errors
Some errors have detailed explanations: E0493, E0723.
For more information about an error, try `rustc --explain E0493`.

View File

@ -0,0 +1,9 @@
struct AlanTuring<T>(T);
const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
//~^ ERROR `impl Trait` in const fn is unstable
AlanTuring(0)
}
const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
fn main() {}

View File

@ -0,0 +1,21 @@
error[E0723]: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn_impl_trait.rs:2:24
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error[E0723]: `impl Trait` in const fn is unstable
--> $DIR/min_const_fn_impl_trait.rs:7:23
|
LL | const fn no_rpit() -> impl std::fmt::Debug {}
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0723`.

View File

@ -1,9 +1,10 @@
trait Trait<'a, 'b> { }
trait Trait<'a, 'b> {}
impl<T> Trait<'_, '_> for T {}
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
//~^ ERROR ambiguous lifetime bound
//~| ERROR ambiguous lifetime bound
(x, y)
}
fn main() { }
fn main() {}

View File

@ -6,5 +6,13 @@ LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
|
= help: add #![feature(member_constraints)] to the crate attributes to enable
error: aborting due to previous error
error: ambiguous lifetime bound in `impl Trait`
--> $DIR/feature-gate-member-constraints.rs:4:43
|
LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
| ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
|
= help: add #![feature(member_constraints)] to the crate attributes to enable
error: aborting due to 2 previous errors

View File

@ -4,9 +4,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0`
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^
|
note: ...which requires borrow-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
@ -15,9 +40,34 @@ note: ...which requires processing `cycle2::{{opaque}}#0`...
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
@ -40,9 +90,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0`
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^
|
note: ...which requires borrow-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
@ -51,9 +126,34 @@ note: ...which requires processing `cycle2::{{opaque}}#0`...
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle
@ -75,9 +175,34 @@ error[E0391]: cycle detected when processing `cycle1::{{opaque}}#0`
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^
|
note: ...which requires borrow-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle1`...
--> $DIR/auto-trait-leak.rs:12:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
@ -86,9 +211,34 @@ note: ...which requires processing `cycle2::{{opaque}}#0`...
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
note: ...which requires borrow-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires type-checking `cycle2`...
--> $DIR/auto-trait-leak.rs:22:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires processing `cycle1::{{opaque}}#0`, completing the cycle

View File

@ -0,0 +1,49 @@
// Test that we consider equal regions when checking for hidden regions in
// opaque types
// check-pass
// `'a == 'static` so `&'a i32` is fine as the return type
fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized {
//~^ WARNING unnecessary lifetime parameter `'a`
x
}
// `'a == 'b` so `&'b i32` is fine as the return type
fn equal_regions<'a: 'b, 'b: 'a>(x: &'b i32) -> impl Sized + 'a {
let y: &'a i32 = x;
let z: &'b i32 = y;
x
}
// `'a == 'b` so `&'a i32` is fine as the return type
fn equal_regions_rev<'a: 'b, 'b: 'a>(x: &'a i32) -> impl Sized + 'b {
let y: &'a i32 = x;
let z: &'b i32 = y;
x
}
// `'a == 'b` so `*mut &'b i32` is fine as the return type
fn equal_regions_inv<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a {
let y: *mut &'a i32 = x;
let z: *mut &'b i32 = y;
x
}
// `'a == 'b` so `*mut &'a i32` is fine as the return type
fn equal_regions_inv_rev<'a: 'b, 'b: 'a>(x: *mut &'a i32) -> impl Sized + 'b {
let y: *mut &'a i32 = x;
let z: *mut &'b i32 = y;
x
}
// Should be able to infer `fn(&'static ())` as the return type.
fn contravariant_lub<'a, 'b: 'a, 'c: 'a, 'd: 'b + 'c>(
x: fn(&'b ()),
y: fn(&'c ()),
c: bool,
) -> impl Sized + 'a {
if c { x } else { y }
}
fn main() {}

View File

@ -0,0 +1,8 @@
warning: unnecessary lifetime parameter `'a`
--> $DIR/equal-hidden-lifetimes.rs:7:25
|
LL | fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized {
| ^^^^^^^^^^^
|
= help: you can use the `'static` lifetime directly, in place of `'a`

View File

@ -0,0 +1,29 @@
// compile-flags:-Zborrowck=mir
#![feature(member_constraints)]
#![feature(type_alias_impl_trait)]
#[derive(Clone)]
struct CopyIfEq<T, U>(T, U);
impl<T: Copy> Copy for CopyIfEq<T, T> {}
type E<'a, 'b> = impl Sized;
fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y);
// This assignment requires that `x` and `y` have the same type due to the
// `Copy` impl. The reason why we are using a copy to create a constraint
// is that only borrow checking (not regionck in type checking) enforces
// this bound.
let u = v;
let _: *mut &'a i32 = u.1;
unsafe {
let _: &'b i32 = *u.0;
}
u.0
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/error-handling-2.rs:13:60
|
LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| ^^^^^^^^^
|
note: hidden type `*mut &'a i32` captures the lifetime `'a` as defined on the function body at 13:8
--> $DIR/error-handling-2.rs:13:8
|
LL | fn foo<'a: 'b, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| ^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0700`.

View File

@ -11,11 +11,18 @@ impl<T: Copy> Copy for CopyIfEq<T, T> {}
type E<'a, 'b> = impl Sized;
fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
//~^ ERROR lifetime may not live long enough
let v = CopyIfEq::<*mut _, *mut _>(&mut {x}, &mut y);
let v = CopyIfEq::<*mut _, *mut _>(&mut { x }, &mut y);
// This assignment requires that `x` and `y` have the same type due to the
// `Copy` impl. The reason why we are using a copy to create a constraint
// is that only borrow checking (not regionck in type checking) enforces
// this bound.
let u = v;
let _: *mut &'a i32 = u.1;
unsafe { let _: &'b i32 = *u.0; }
unsafe {
let _: &'b i32 = *u.0;
//~^ ERROR lifetime may not live long enough
}
u.0
}

View File

@ -1,14 +1,15 @@
error: lifetime may not live long enough
--> $DIR/error-handling.rs:13:56
--> $DIR/error-handling.rs:23:16
|
LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
| -- lifetime `'a` defined here ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
|
= help: consider replacing `'a` with `'static`
help: to allow this `impl Trait` to capture borrowed data with lifetime `'a`, add `'a` as a bound
|
LL | type E<'a, 'b> = impl Sized + 'a;
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
...
LL | let _: &'b i32 = *u.0;
| ^^^^^^^ type annotation requires that `'a` must outlive `'b`
|
= help: consider adding the following bound: `'a: 'b`
error: aborting due to previous error

View File

@ -3,6 +3,8 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
|
LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
| ^^^^^^^^^^^^^^^^^^
|
= note: hidden type `Ordinary<'_>` captures lifetime '_#8r
error: aborting due to previous error

View File

@ -3,6 +3,8 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
|
LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
| ^^^^^^^^^^^^^^^^^^
|
= note: hidden type `Ordinary<'_>` captures lifetime '_#5r
error: aborting due to previous error

View File

@ -0,0 +1,16 @@
// Check that nested impl Trait items work in functions with generic parameters.
// check-pass
trait Captures<'a> {}
impl<T> Captures<'_> for T {}
fn nested_assoc_type<'a: 'a, T>() -> impl Iterator<Item = impl Sized> {
[1].iter()
}
fn nested_assoc_lifetime<'a: 'a, T>() -> impl Iterator<Item = impl Captures<'a>> {
[1].iter()
}
fn main() {}

View File

@ -1,6 +1,9 @@
// Test that an `impl Trait` type that expands to itself is an error.
fn test() -> impl Sized { //~ ERROR E0720
#![allow(unconditional_recursion)]
fn test() -> impl Sized {
//~^ ERROR E0720
test()
}

View File

@ -1,5 +1,5 @@
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-direct.rs:3:14
--> $DIR/recursive-impl-trait-type-direct.rs:5:14
|
LL | fn test() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type

View File

@ -2,59 +2,75 @@
// otherwise forbidden.
#![feature(generators)]
#![allow(unconditional_recursion)]
fn option(i: i32) -> impl Sized { //~ ERROR
if i < 0 {
None
} else {
Some((option(i - 1), i))
}
fn option(i: i32) -> impl Sized {
//~^ ERROR
if i < 0 { None } else { Some((option(i - 1), i)) }
}
fn tuple() -> impl Sized { //~ ERROR
fn tuple() -> impl Sized {
//~^ ERROR
(tuple(),)
}
fn array() -> impl Sized { //~ ERROR
fn array() -> impl Sized {
//~^ ERROR
[array()]
}
fn ptr() -> impl Sized { //~ ERROR
fn ptr() -> impl Sized {
//~^ ERROR
&ptr() as *const _
}
fn fn_ptr() -> impl Sized { //~ ERROR
fn fn_ptr() -> impl Sized {
//~^ ERROR
fn_ptr as fn() -> _
}
fn closure_capture() -> impl Sized { //~ ERROR
fn closure_capture() -> impl Sized {
//~^ ERROR
let x = closure_capture();
move || { x; }
move || {
x;
}
}
fn closure_ref_capture() -> impl Sized { //~ ERROR
fn closure_ref_capture() -> impl Sized {
//~^ ERROR
let x = closure_ref_capture();
move || { &x; }
move || {
&x;
}
}
fn closure_sig() -> impl Sized { //~ ERROR
fn closure_sig() -> impl Sized {
//~^ ERROR
|| closure_sig()
}
fn generator_sig() -> impl Sized { //~ ERROR
fn generator_sig() -> impl Sized {
//~^ ERROR
|| generator_sig()
}
fn generator_capture() -> impl Sized { //~ ERROR
fn generator_capture() -> impl Sized {
//~^ ERROR
let x = generator_capture();
move || { yield; x; }
move || {
yield;
x;
}
}
fn substs_change<T>() -> impl Sized { //~ ERROR
fn substs_change<T: 'static>() -> impl Sized {
//~^ ERROR
(substs_change::<&T>(),)
}
fn generator_hold() -> impl Sized { //~ ERROR
fn generator_hold() -> impl Sized {
//~^ ERROR
move || {
let x = generator_hold();
yield;
@ -62,15 +78,18 @@ fn generator_hold() -> impl Sized { //~ ERROR
}
}
fn use_fn_ptr() -> impl Sized { // OK, error already reported
fn use_fn_ptr() -> impl Sized {
// OK, error already reported
fn_ptr()
}
fn mutual_recursion() -> impl Sync { //~ ERROR
fn mutual_recursion() -> impl Sync {
//~^ ERROR
mutual_recursion_b()
}
fn mutual_recursion_b() -> impl Sized { //~ ERROR
fn mutual_recursion_b() -> impl Sized {
//~^ ERROR
mutual_recursion()
}

View File

@ -1,5 +1,5 @@
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:6:22
--> $DIR/recursive-impl-trait-type-indirect.rs:7:22
|
LL | fn option(i: i32) -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
@ -7,7 +7,7 @@ LL | fn option(i: i32) -> impl Sized {
= note: expanded type is `std::option::Option<(impl Sized, i32)>`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:14:15
--> $DIR/recursive-impl-trait-type-indirect.rs:12:15
|
LL | fn tuple() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
@ -15,7 +15,7 @@ LL | fn tuple() -> impl Sized {
= note: expanded type is `(impl Sized,)`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:18:15
--> $DIR/recursive-impl-trait-type-indirect.rs:17:15
|
LL | fn array() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
@ -31,7 +31,7 @@ LL | fn ptr() -> impl Sized {
= note: expanded type is `*const impl Sized`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:26:16
--> $DIR/recursive-impl-trait-type-indirect.rs:27:16
|
LL | fn fn_ptr() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
@ -39,63 +39,63 @@ LL | fn fn_ptr() -> impl Sized {
= note: expanded type is `fn() -> impl Sized`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:30:25
--> $DIR/recursive-impl-trait-type-indirect.rs:32:25
|
LL | fn closure_capture() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:32:5: 32:19 x:impl Sized]`
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:35:29
--> $DIR/recursive-impl-trait-type-indirect.rs:40:29
|
LL | fn closure_ref_capture() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:37:5: 37:20 x:impl Sized]`
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:40:21
--> $DIR/recursive-impl-trait-type-indirect.rs:48:21
|
LL | fn closure_sig() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:41:5: 41:21]`
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:21]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:44:23
--> $DIR/recursive-impl-trait-type-indirect.rs:53:23
|
LL | fn generator_sig() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:45:5: 45:23]`
= note: expanded type is `[closure@$DIR/recursive-impl-trait-type-indirect.rs:55:5: 55:23]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:48:27
--> $DIR/recursive-impl-trait-type-indirect.rs:58:27
|
LL | fn generator_capture() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:50:5: 50:26 x:impl Sized {()}]`
= note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:53:26
--> $DIR/recursive-impl-trait-type-indirect.rs:67:35
|
LL | fn substs_change<T>() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
LL | fn substs_change<T: 'static>() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `(impl Sized,)`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:57:24
--> $DIR/recursive-impl-trait-type-indirect.rs:72:24
|
LL | fn generator_hold() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type
|
= note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:58:5: 62:6 {impl Sized, ()}]`
= note: expanded type is `[generator@$DIR/recursive-impl-trait-type-indirect.rs:74:5: 78:6 {impl Sized, ()}]`
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:69:26
--> $DIR/recursive-impl-trait-type-indirect.rs:86:26
|
LL | fn mutual_recursion() -> impl Sync {
| ^^^^^^^^^ expands to a recursive type
@ -103,7 +103,7 @@ LL | fn mutual_recursion() -> impl Sync {
= note: type resolves to itself
error[E0720]: opaque type expands to a recursive type
--> $DIR/recursive-impl-trait-type-indirect.rs:73:28
--> $DIR/recursive-impl-trait-type-indirect.rs:91:28
|
LL | fn mutual_recursion_b() -> impl Sized {
| ^^^^^^^^^^ expands to a recursive type

View File

@ -0,0 +1,32 @@
// Ensure that we don't get a cycle error from trying to determine whether an
// opaque type implements `Freeze` in safety checking, when it doesn't matter.
// check-pass
#![feature(rustc_attrs)]
struct AnyValue<T>(T);
// No need to check for `Freeze` here, there's no
// `rustc_layout_scalar_valid_range_start` involved.
fn not_restricted(c: bool) -> impl Sized {
if c {
let x = AnyValue(not_restricted(false));
&x.0;
}
2u32
}
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>(T);
// No need to check for `Freeze` here, we're not borrowing the field.
fn not_field(c: bool) -> impl Sized {
if c {
let x = unsafe { NonZero(not_field(false)) };
&x;
}
5u32
}
fn main() {}

View File

@ -2,17 +2,17 @@
// Exercise the unused_mut attribute in some positive and negative cases
#![deny(unused_mut)]
#![warn(unused_mut)]
#![feature(async_closure, raw_ref_op)]
async fn baz_async(
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
) {}
fn baz(
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
#[allow(unused_mut)] (mut c, d): (i32, i32)
) {}
@ -21,13 +21,13 @@ struct RefStruct {}
impl RefStruct {
async fn baz_async(
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
) {}
fn baz(
&self,
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
#[allow(unused_mut)] (mut c, d): (i32, i32)
) {}
@ -37,7 +37,7 @@ trait RefTrait {
fn baz(
&self,
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
#[allow(unused_mut)] (mut c, d): (i32, i32)
) {}
@ -46,7 +46,7 @@ impl RefTrait for () {
fn baz(
&self,
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
#[allow(unused_mut)] (mut c, d): (i32, i32)
) {}
@ -55,32 +55,32 @@ impl RefTrait for () {
fn main() {
let _ = async move |
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
| {};
let _ = |
mut a: i32,
//~^ ERROR: variable does not need to be mutable
//~^ WARN: variable does not need to be mutable
#[allow(unused_mut)] mut b: i32,
#[allow(unused_mut)] (mut c, d): (i32, i32)
| {};
// negative cases
let mut a = 3; //~ ERROR: variable does not need to be mutable
let mut a = 3; //~ WARN: variable does not need to be mutable
let mut a = 2; //~ ERROR: variable does not need to be mutable
let mut a = 2; //~ WARN: variable does not need to be mutable
let mut b = 3; //~ ERROR: variable does not need to be mutable
let mut b = 3; //~ WARN: variable does not need to be mutable
let mut a = vec![3]; //~ ERROR: variable does not need to be mutable
let mut a = vec![3]; //~ WARN: variable does not need to be mutable
let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable
let (mut a, b) = (1, 2); //~ WARN: variable does not need to be mutable
let mut a; //~ ERROR: variable does not need to be mutable
let mut a; //~ WARN: variable does not need to be mutable
a = 3;
let mut b; //~ ERROR: variable does not need to be mutable
let mut b; //~ WARN: variable does not need to be mutable
if true {
b = 3;
@ -89,11 +89,11 @@ fn main() {
}
match 30 {
mut x => {} //~ ERROR: variable does not need to be mutable
mut x => {} //~ WARN: variable does not need to be mutable
}
match (30, 2) {
(mut x, 1) | //~ ERROR: variable does not need to be mutable
(mut x, 1) | //~ WARN: variable does not need to be mutable
(mut x, 2) |
(mut x, 3) => {
@ -101,20 +101,20 @@ fn main() {
_ => {}
}
let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable
let x = |mut y: isize| 10; //~ WARN: variable does not need to be mutable
fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable
fn what(mut foo: isize) {} //~ WARN: variable does not need to be mutable
let mut a = &mut 5; //~ ERROR: variable does not need to be mutable
let mut a = &mut 5; //~ WARN: variable does not need to be mutable
*a = 4;
let mut a = 5;
let mut b = (&mut a,); //~ ERROR: variable does not need to be mutable
let mut b = (&mut a,); //~ WARN: variable does not need to be mutable
*b.0 = 4;
let mut x = &mut 1; //~ ERROR: variable does not need to be mutable
let mut x = &mut 1; //~ WARN: variable does not need to be mutable
let mut f = || {
*x += 1;
@ -122,11 +122,11 @@ fn main() {
f();
fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
&mut arg[..] //~^ ERROR: variable does not need to be mutable
&mut arg[..] //~^ WARN: variable does not need to be mutable
}
let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable
let mut v : &mut Vec<()> = &mut vec![]; //~ WARN: variable does not need to be mutable
v.push(());
@ -181,7 +181,7 @@ fn main() {
let mut raw_address_of_mut = 1; // OK
let mut_ptr = &raw mut raw_address_of_mut;
let mut raw_address_of_const = 1; //~ ERROR: variable does not need to be mutable
let mut raw_address_of_const = 1; //~ WARN: variable does not need to be mutable
let const_ptr = &raw const raw_address_of_const;
}

View File

@ -1,4 +1,4 @@
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:9:5
|
LL | mut a: i32,
@ -9,18 +9,10 @@ LL | mut a: i32,
note: the lint level is defined here
--> $DIR/lint-unused-mut-variables.rs:5:9
|
LL | #![deny(unused_mut)]
LL | #![warn(unused_mut)]
| ^^^^^^^^^^
error: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:14:5
|
LL | mut a: i32,
| ----^
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:23:9
|
LL | mut a: i32,
@ -28,7 +20,15 @@ LL | mut a: i32,
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:14:5
|
LL | mut a: i32,
| ----^
| |
| help: remove this `mut`
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:29:9
|
LL | mut a: i32,
@ -36,7 +36,7 @@ LL | mut a: i32,
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:39:9
|
LL | mut a: i32,
@ -44,7 +44,7 @@ LL | mut a: i32,
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:48:9
|
LL | mut a: i32,
@ -52,7 +52,7 @@ LL | mut a: i32,
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:57:9
|
LL | mut a: i32,
@ -60,7 +60,7 @@ LL | mut a: i32,
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:62:9
|
LL | mut a: i32,
@ -68,7 +68,7 @@ LL | mut a: i32,
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:104:14
|
LL | let x = |mut y: isize| 10;
@ -76,7 +76,7 @@ LL | let x = |mut y: isize| 10;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:69:9
|
LL | let mut a = 3;
@ -84,7 +84,7 @@ LL | let mut a = 3;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:71:9
|
LL | let mut a = 2;
@ -92,7 +92,7 @@ LL | let mut a = 2;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:73:9
|
LL | let mut b = 3;
@ -100,7 +100,7 @@ LL | let mut b = 3;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:75:9
|
LL | let mut a = vec![3];
@ -108,7 +108,7 @@ LL | let mut a = vec![3];
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:77:10
|
LL | let (mut a, b) = (1, 2);
@ -116,7 +116,7 @@ LL | let (mut a, b) = (1, 2);
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:79:9
|
LL | let mut a;
@ -124,7 +124,7 @@ LL | let mut a;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:83:9
|
LL | let mut b;
@ -132,7 +132,7 @@ LL | let mut b;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:92:9
|
LL | mut x => {}
@ -140,7 +140,7 @@ LL | mut x => {}
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:96:8
|
LL | (mut x, 1) |
@ -148,7 +148,7 @@ LL | (mut x, 1) |
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:109:9
|
LL | let mut a = &mut 5;
@ -156,7 +156,7 @@ LL | let mut a = &mut 5;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:114:9
|
LL | let mut b = (&mut a,);
@ -164,7 +164,7 @@ LL | let mut b = (&mut a,);
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:117:9
|
LL | let mut x = &mut 1;
@ -172,7 +172,7 @@ LL | let mut x = &mut 1;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:129:9
|
LL | let mut v : &mut Vec<()> = &mut vec![];
@ -180,7 +180,7 @@ LL | let mut v : &mut Vec<()> = &mut vec![];
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:184:9
|
LL | let mut raw_address_of_const = 1;
@ -188,7 +188,7 @@ LL | let mut raw_address_of_const = 1;
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:106:13
|
LL | fn what(mut foo: isize) {}
@ -196,7 +196,7 @@ LL | fn what(mut foo: isize) {}
| |
| help: remove this `mut`
error: variable does not need to be mutable
warning: variable does not need to be mutable
--> $DIR/lint-unused-mut-variables.rs:124:20
|
LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
@ -218,5 +218,5 @@ note: the lint level is defined here
LL | #[deny(unused_mut)]
| ^^^^^^^^^^
error: aborting due to 26 previous errors
error: aborting due to previous error

View File

@ -1,11 +1,3 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:45
|
LL | async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
|
@ -24,14 +16,6 @@ LL | async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (
| | let's call the lifetime of this reference `'1`
| let's call the lifetime of this reference `'2`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:58
|
LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
| ^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
|
@ -41,6 +25,5 @@ LL | async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
| | let's call the lifetime of this reference `'1`
| lifetime `'a` defined here
error: aborting due to 5 previous errors
error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -1,11 +1,3 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:12:42
|
LL | async fn ref_self(&self, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:13:9
|
@ -16,14 +8,6 @@ LL | async fn ref_self(&self, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:18:48
|
LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:19:9
|
@ -34,14 +18,6 @@ LL | async fn ref_Self(self: &Self, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:22:57
|
LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:23:9
|
@ -52,14 +28,6 @@ LL | async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:26:57
|
LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:27:9
|
@ -70,14 +38,6 @@ LL | async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:30:66
|
LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:31:9
|
@ -88,14 +48,6 @@ LL | async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/lt-ref-self-async.rs:34:62
|
LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#23r
error: lifetime may not live long enough
--> $DIR/lt-ref-self-async.rs:35:9
|
@ -106,6 +58,5 @@ LL | async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: aborting due to 12 previous errors
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -1,11 +1,3 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-self-async.rs:12:46
|
LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:13:9
|
@ -16,14 +8,6 @@ LL | async fn ref_self(&mut self, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-self-async.rs:18:52
|
LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:19:9
|
@ -34,14 +18,6 @@ LL | async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-self-async.rs:22:61
|
LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:23:9
|
@ -52,14 +28,6 @@ LL | async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-self-async.rs:26:61
|
LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:27:9
|
@ -70,14 +38,6 @@ LL | async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-self-async.rs:30:70
|
LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:31:9
|
@ -88,14 +48,6 @@ LL | async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-self-async.rs:34:70
|
LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-self-async.rs:35:9
|
@ -106,6 +58,5 @@ LL | async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: aborting due to 12 previous errors
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -1,11 +1,3 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-struct-async.rs:12:56
|
LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:13:9
|
@ -16,14 +8,6 @@ LL | async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-struct-async.rs:16:65
|
LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:17:9
|
@ -34,14 +18,6 @@ LL | async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-struct-async.rs:20:65
|
LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:21:9
|
@ -52,14 +28,6 @@ LL | async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-struct-async.rs:24:74
|
LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:25:9
|
@ -70,14 +38,6 @@ LL | async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-mut-struct-async.rs:28:74
|
LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-mut-struct-async.rs:29:9
|
@ -88,6 +48,5 @@ LL | async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: aborting due to 10 previous errors
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -1,11 +1,3 @@
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-struct-async.rs:12:52
|
LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:13:9
|
@ -16,14 +8,6 @@ LL | async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-struct-async.rs:16:61
|
LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:17:9
|
@ -34,14 +18,6 @@ LL | async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-struct-async.rs:20:61
|
LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:21:9
|
@ -52,14 +28,6 @@ LL | async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-struct-async.rs:24:70
|
LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:25:9
|
@ -70,14 +38,6 @@ LL | async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
--> $DIR/ref-struct-async.rs:28:66
|
LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
| ^^^^
|
= note: hidden type `impl std::future::Future` captures lifetime '_#15r
error: lifetime may not live long enough
--> $DIR/ref-struct-async.rs:29:9
|
@ -88,6 +48,5 @@ LL | async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
LL | f
| ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
error: aborting due to 10 previous errors
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0700`.

View File

@ -6,7 +6,7 @@
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
trait UnwrapItemsExt<const C: usize> {
trait UnwrapItemsExt<'a, const C: usize> {
type Iter;
fn unwrap_items(self) -> Self::Iter;
}
@ -18,18 +18,16 @@ trait MyTrait<'a, const C: usize> {
const MY_CONST: usize;
}
impl<'a, const C: usize> MyTrait<'a, {C}> for MyStruct<{C}> {
impl<'a, const C: usize> MyTrait<'a, { C }> for MyStruct<{ C }> {
type MyItem = u8;
const MY_CONST: usize = C;
}
impl<'a, I, const C: usize> UnwrapItemsExt<{C}> for I
where
{
type Iter = impl MyTrait<'a, {C}>;
impl<'a, I, const C: usize> UnwrapItemsExt<'a, { C }> for I {
type Iter = impl MyTrait<'a, { C }>;
fn unwrap_items(self) -> Self::Iter {
MyStruct::<{C}> {}
MyStruct::<{ C }> {}
}
}

View File

@ -0,0 +1,26 @@
// Tests that we don't allow unconstrained lifetime parameters in impls when
// the lifetime is used in an associated opaque type.
#![feature(type_alias_impl_trait)]
trait UnwrapItemsExt {
type Iter;
fn unwrap_items(self) -> Self::Iter;
}
struct MyStruct {}
trait MyTrait<'a> {}
impl<'a> MyTrait<'a> for MyStruct {}
impl<'a, I> UnwrapItemsExt for I {
//~^ ERROR the lifetime parameter `'a` is not constrained
type Iter = impl MyTrait<'a>;
fn unwrap_items(self) -> Self::Iter {
MyStruct {}
}
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
--> $DIR/assoc-type-lifetime-unconstrained.rs:17:6
|
LL | impl<'a, I> UnwrapItemsExt for I {
| ^^ unconstrained lifetime parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0207`.

View File

@ -4,7 +4,7 @@
#![feature(type_alias_impl_trait)]
trait UnwrapItemsExt {
trait UnwrapItemsExt<'a> {
type Iter;
fn unwrap_items(self) -> Self::Iter;
}
@ -15,9 +15,7 @@ trait MyTrait<'a> {}
impl<'a> MyTrait<'a> for MyStruct {}
impl<'a, I> UnwrapItemsExt for I
where
{
impl<'a, I> UnwrapItemsExt<'a> for I {
type Iter = impl MyTrait<'a>;
fn unwrap_items(self) -> Self::Iter {

View File

@ -7,11 +7,11 @@ fn main() {}
// test that unused generic parameters are ok
type Two<T, U> = impl Debug;
fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
(t, t)
}
fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
//~^ concrete type differs from previous
fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
//~^ concrete type differs from previous
(u, t)
}

View File

@ -1,7 +1,7 @@
error: concrete type differs from previous defining opaque type use
--> $DIR/generic_duplicate_param_use6.rs:14:1
|
LL | / fn three<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
LL | / fn three<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
LL | |
LL | | (u, t)
LL | | }
@ -10,7 +10,7 @@ LL | | }
note: previous use here
--> $DIR/generic_duplicate_param_use6.rs:10:1
|
LL | / fn two<T: Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
LL | / fn two<T: Copy + Debug, U: Debug>(t: T, u: U) -> Two<T, U> {
LL | | (t, t)
LL | | }
| |_^

View File

@ -7,7 +7,7 @@ use std::fmt::Debug;
fn main() {
type Opaque = impl Debug;
fn _unused() -> Opaque { String::new() }
//~^ ERROR: concrete type differs from previous defining opaque type use
let null = || -> Opaque { 0 };
//~^ ERROR: concrete type differs from previous defining opaque type use
println!("{:?}", null());
}

View File

@ -1,20 +1,14 @@
error: concrete type differs from previous defining opaque type use
--> $DIR/issue-52843-closure-constrain.rs:10:16
|
LL | let null = || -> Opaque { 0 };
| ^^^^^^^^^^^^^^^^^^ expected `std::string::String`, got `i32`
|
note: previous use here
--> $DIR/issue-52843-closure-constrain.rs:9:5
|
LL | fn _unused() -> Opaque { String::new() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, got `std::string::String`
|
note: previous use here
--> $DIR/issue-52843-closure-constrain.rs:7:1
|
LL | / fn main() {
LL | | type Opaque = impl Debug;
LL | | fn _unused() -> Opaque { String::new() }
LL | |
LL | | let null = || -> Opaque { 0 };
LL | | println!("{:?}", null());
LL | | }
| |_^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View File

@ -8,7 +8,7 @@ trait IterBits {
type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
//~^ ERROR could not find defining uses
impl<T, E> IterBits for T
impl<T: Copy, E> IterBits for T
where
T: std::ops::Shr<Output = T>
+ std::ops::BitAnd<T, Output = T>