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:
commit
19288ddfd6
@ -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,
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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<®ion::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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]>,
|
||||
}
|
||||
|
@ -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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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()
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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, ®ioncx, &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, ®ioncx, &opt_closure_req, &mut errors_buffer);
|
||||
nll::dump_annotation(
|
||||
infcx,
|
||||
&body,
|
||||
def_id,
|
||||
®ioncx,
|
||||
&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,
|
||||
};
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
});
|
||||
|
149
src/librustc_mir/borrow_check/region_infer/opaque_types.rs
Normal file
149
src/librustc_mir/borrow_check/region_infer/opaque_types.rs
Normal 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,
|
||||
})
|
||||
}
|
||||
}
|
68
src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs
Normal file
68
src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs
Normal 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
|
||||
}
|
||||
}
|
@ -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),
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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> {
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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 ¶m.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()
|
||||
|
661
src/librustc_typeck/collect/type_of.rs
Normal file
661
src/librustc_typeck/collect/type_of.rs
Normal 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 ¶m.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();
|
||||
}
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
|
@ -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`.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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`.
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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`.
|
||||
|
@ -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`
|
||||
|
@ -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`.
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -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() {}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
49
src/test/ui/impl-trait/equal-hidden-lifetimes.rs
Normal file
49
src/test/ui/impl-trait/equal-hidden-lifetimes.rs
Normal 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() {}
|
8
src/test/ui/impl-trait/equal-hidden-lifetimes.stderr
Normal file
8
src/test/ui/impl-trait/equal-hidden-lifetimes.stderr
Normal 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`
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
16
src/test/ui/impl-trait/nested-return-type.rs
Normal file
16
src/test/ui/impl-trait/nested-return-type.rs
Normal 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() {}
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
32
src/test/ui/impl-trait/unsafety-checking-cycle.rs
Normal file
32
src/test/ui/impl-trait/unsafety-checking-cycle.rs
Normal 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() {}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
||||
|
@ -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`.
|
||||
|
@ -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 }> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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() {}
|
@ -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`.
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 | | }
|
||||
| |_^
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user