mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Handle impl trait in MIR type checked for assignments.
This commit is contained in:
parent
cf915849f0
commit
218189536d
@ -1739,7 +1739,7 @@ specified exit code, use `std::process::exit`.
|
||||
|
||||
E0562: r##"
|
||||
Abstract return types (written `impl Trait` for some trait `Trait`) are only
|
||||
allowed as function and inherent impl return types or binding types.
|
||||
allowed as function and inherent impl return types.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
@ -1754,8 +1754,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Make sure `impl Trait` only appears in return-type position or as the type of a
|
||||
binding.
|
||||
Make sure `impl Trait` only appears in return-type position.
|
||||
|
||||
```
|
||||
fn count_to_n(n: usize) -> impl Iterator<Item=usize> {
|
||||
|
@ -1284,12 +1284,18 @@ impl<'a> LoweringContext<'a> {
|
||||
))
|
||||
}
|
||||
ImplTraitContext::Disallowed => {
|
||||
let allowed_in = if self.sess.features_untracked()
|
||||
.impl_trait_in_bindings {
|
||||
"bindings or function and inherent method return types"
|
||||
} else {
|
||||
"function and inherent method return types"
|
||||
};
|
||||
span_err!(
|
||||
self.sess,
|
||||
t.span,
|
||||
E0562,
|
||||
"`impl Trait` not allowed outside of function \
|
||||
and inherent method return types or bindings"
|
||||
"`impl Trait` not allowed outside of {}",
|
||||
allowed_in,
|
||||
);
|
||||
hir::TyKind::Err
|
||||
}
|
||||
@ -2206,8 +2212,10 @@ impl<'a> LoweringContext<'a> {
|
||||
let impl_trait_ty = self.lower_existential_impl_trait(
|
||||
span, Some(fn_def_id), return_impl_trait_id, |this| {
|
||||
let output_ty = match output {
|
||||
FunctionRetTy::Ty(ty) =>
|
||||
this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))),
|
||||
FunctionRetTy::Ty(ty) => {
|
||||
let impl_trait_owner_id = *this.current_impl_trait_owner.last().unwrap();
|
||||
this.lower_ty(ty, ImplTraitContext::Existential(Some(impl_trait_owner_id)))
|
||||
}
|
||||
FunctionRetTy::Default(span) => {
|
||||
let LoweredNodeId { node_id, hir_id } = this.next_id();
|
||||
P(hir::Ty {
|
||||
@ -2702,14 +2710,31 @@ impl<'a> LoweringContext<'a> {
|
||||
ItemKind::Static(ref t, m, ref e) => {
|
||||
let value = self.lower_body(None, |this| this.lower_expr(e));
|
||||
hir::ItemKind::Static(
|
||||
self.lower_ty(t, ImplTraitContext::Disallowed),
|
||||
self.lower_ty(
|
||||
t,
|
||||
if self.sess.features_untracked().impl_trait_in_bindings {
|
||||
ImplTraitContext::Existential(None)
|
||||
} else {
|
||||
ImplTraitContext::Disallowed
|
||||
}
|
||||
),
|
||||
self.lower_mutability(m),
|
||||
value,
|
||||
)
|
||||
}
|
||||
ItemKind::Const(ref t, ref e) => {
|
||||
let value = self.lower_body(None, |this| this.lower_expr(e));
|
||||
hir::ItemKind::Const(self.lower_ty(t, ImplTraitContext::Disallowed), value)
|
||||
hir::ItemKind::Const(
|
||||
self.lower_ty(
|
||||
t,
|
||||
if self.sess.features_untracked().impl_trait_in_bindings {
|
||||
ImplTraitContext::Existential(None)
|
||||
} else {
|
||||
ImplTraitContext::Disallowed
|
||||
}
|
||||
),
|
||||
value
|
||||
)
|
||||
}
|
||||
ItemKind::Fn(ref decl, header, ref generics, ref body) => {
|
||||
let fn_def_id = self.resolver.definitions().local_def_id(id);
|
||||
@ -3258,6 +3283,22 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
ids
|
||||
},
|
||||
ItemKind::Static(ref ty, ..) => {
|
||||
let mut ids = smallvec![hir::ItemId { id: i.id }];
|
||||
if self.sess.features_untracked().impl_trait_in_bindings {
|
||||
let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
ids
|
||||
},
|
||||
ItemKind::Const(ref ty, ..) => {
|
||||
let mut ids = smallvec![hir::ItemId { id: i.id }];
|
||||
if self.sess.features_untracked().impl_trait_in_bindings {
|
||||
let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids };
|
||||
visitor.visit_ty(ty);
|
||||
}
|
||||
ids
|
||||
},
|
||||
_ => smallvec![hir::ItemId { id: i.id }],
|
||||
}
|
||||
}
|
||||
@ -3817,8 +3858,8 @@ impl<'a> LoweringContext<'a> {
|
||||
}
|
||||
ExprKind::Block(ref blk, opt_label) => {
|
||||
hir::ExprKind::Block(self.lower_block(blk,
|
||||
opt_label.is_some()),
|
||||
self.lower_label(opt_label))
|
||||
opt_label.is_some()),
|
||||
self.lower_label(opt_label))
|
||||
}
|
||||
ExprKind::Assign(ref el, ref er) => {
|
||||
hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er)))
|
||||
|
@ -361,7 +361,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
||||
let tcx = relation.tcx();
|
||||
let a_sty = &a.sty;
|
||||
let b_sty = &b.sty;
|
||||
debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
|
||||
debug!("super_relate_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
|
||||
match (a_sty, b_sty) {
|
||||
(&ty::Infer(_), _) |
|
||||
(_, &ty::Infer(_)) =>
|
||||
|
@ -17,15 +17,8 @@
|
||||
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
|
||||
//! contain revealed `impl Trait` values).
|
||||
|
||||
use borrow_check::nll::renumber;
|
||||
use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::mir::*;
|
||||
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::Ty;
|
||||
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
@ -37,16 +30,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
pub(super) fn equate_inputs_and_outputs(
|
||||
&mut self,
|
||||
mir: &Mir<'tcx>,
|
||||
mir_def_id: DefId,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
universal_region_relations: &UniversalRegionRelations<'tcx>,
|
||||
normalized_inputs_and_output: &[Ty<'tcx>],
|
||||
) {
|
||||
let tcx = self.infcx.tcx;
|
||||
|
||||
let (&normalized_output_ty, normalized_input_tys) =
|
||||
normalized_inputs_and_output.split_last().unwrap();
|
||||
let infcx = self.infcx;
|
||||
|
||||
// Equate expected input tys with those in the MIR.
|
||||
let argument_locals = (1..).map(Local::new);
|
||||
@ -77,111 +65,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
|
||||
// Return types are a bit more complex. They may contain existential `impl Trait`
|
||||
// types.
|
||||
let param_env = self.param_env;
|
||||
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
|
||||
let output_span = mir.local_decls[RETURN_PLACE].source_info.span;
|
||||
let opaque_type_map =
|
||||
self.fully_perform_op(
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
let (output_ty, opaque_type_map) =
|
||||
obligations.add(infcx.instantiate_opaque_types(
|
||||
mir_def_id,
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
&normalized_output_ty,
|
||||
));
|
||||
debug!(
|
||||
"equate_inputs_and_outputs: instantiated output_ty={:?}",
|
||||
output_ty
|
||||
);
|
||||
debug!(
|
||||
"equate_inputs_and_outputs: opaque_type_map={:#?}",
|
||||
opaque_type_map
|
||||
);
|
||||
|
||||
debug!(
|
||||
"equate_inputs_and_outputs: mir_output_ty={:?}",
|
||||
mir_output_ty
|
||||
);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, mir_output_ty)?,
|
||||
);
|
||||
|
||||
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,
|
||||
);
|
||||
debug!(
|
||||
"equate_inputs_and_outputs: concrete_ty={:?}",
|
||||
opaque_decl.concrete_ty
|
||||
);
|
||||
debug!("equate_inputs_and_outputs: opaque_defn_ty={:?}",
|
||||
opaque_defn_ty);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
|
||||
);
|
||||
}
|
||||
|
||||
debug!("equate_inputs_and_outputs: equated");
|
||||
|
||||
Ok(InferOk {
|
||||
value: Some(opaque_type_map),
|
||||
obligations: obligations.into_vec(),
|
||||
})
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
).unwrap_or_else(|terr| {
|
||||
span_mirbug!(
|
||||
self,
|
||||
Location::START,
|
||||
"equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
|
||||
normalized_output_ty,
|
||||
mir_output_ty,
|
||||
terr
|
||||
);
|
||||
None
|
||||
});
|
||||
|
||||
// Finally, if we instantiated the opaque types successfully, we
|
||||
// have to solve any bounds (e.g., `-> impl Iterator` needs to
|
||||
// prove that `T: Iterator` where `T` is the type we
|
||||
// instantiated it with).
|
||||
if let Some(opaque_type_map) = opaque_type_map {
|
||||
for (opaque_def_id, opaque_decl) in opaque_type_map {
|
||||
self.fully_perform_op(
|
||||
Locations::All(infcx.tcx.def_span(opaque_def_id)),
|
||||
ConstraintCategory::OpaqueType,
|
||||
CustomTypeOp::new(
|
||||
|_cx| {
|
||||
infcx.constrain_opaque_type(
|
||||
opaque_def_id,
|
||||
&opaque_decl,
|
||||
universal_region_relations
|
||||
);
|
||||
Ok(InferOk {
|
||||
value: (),
|
||||
obligations: vec![],
|
||||
})
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
if let Err(terr) = self.eq_opaque_type_and_type(
|
||||
mir_output_ty,
|
||||
normalized_output_ty,
|
||||
Locations::All(output_span),
|
||||
ConstraintCategory::BoringNoLocation,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
Location::START,
|
||||
"equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
|
||||
normalized_output_ty,
|
||||
mir_output_ty,
|
||||
terr
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
|
||||
@ -204,20 +104,3 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ObligationAccumulator<'tcx> {
|
||||
obligations: PredicateObligations<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationAccumulator<'tcx> {
|
||||
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
|
||||
let InferOk { value, obligations } = value;
|
||||
self.obligations.extend(obligations);
|
||||
value
|
||||
}
|
||||
|
||||
fn into_vec(self) -> PredicateObligations<'tcx> {
|
||||
self.obligations
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ use borrow_check::nll::type_check::free_region_relations::{
|
||||
};
|
||||
use borrow_check::nll::universal_regions::UniversalRegions;
|
||||
use borrow_check::nll::ToRegionVid;
|
||||
use borrow_check::nll::renumber;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use dataflow::FlowAtLocation;
|
||||
use dataflow::MaybeInitializedPlaces;
|
||||
@ -29,15 +30,18 @@ use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::canonical::QueryRegionConstraint;
|
||||
use rustc::infer::region_constraints::GenericKind;
|
||||
use rustc::infer::{InferCtxt, LateBoundRegionConversionTime};
|
||||
use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||
use rustc::mir::interpret::EvalErrorKind::BoundsCheck;
|
||||
use rustc::mir::tcx::PlaceTy;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::*;
|
||||
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||
use rustc::traits::query::type_op;
|
||||
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc::traits::query::{Fallible, NoSolution};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
||||
use rustc::ty::subst::Subst;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
@ -155,12 +159,11 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
||||
®ion_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
Some(&mut borrowck_context),
|
||||
Some(&universal_region_relations),
|
||||
|cx| {
|
||||
cx.equate_inputs_and_outputs(
|
||||
mir,
|
||||
mir_def_id,
|
||||
universal_regions,
|
||||
&universal_region_relations,
|
||||
&normalized_inputs_and_output,
|
||||
);
|
||||
liveness::generate(cx, mir, elements, flow_inits, move_data);
|
||||
@ -182,6 +185,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||
mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R,
|
||||
) -> R where {
|
||||
let mut checker = TypeChecker::new(
|
||||
@ -192,6 +196,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
universal_region_relations,
|
||||
);
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
||||
@ -692,6 +697,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||
}
|
||||
|
||||
struct BorrowCheckContext<'a, 'tcx: 'a> {
|
||||
@ -799,6 +805,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||
) -> Self {
|
||||
TypeChecker {
|
||||
infcx,
|
||||
@ -810,6 +817,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
implicit_region_bound,
|
||||
borrowck_context,
|
||||
reported_errors: FxHashSet(),
|
||||
universal_region_relations,
|
||||
}
|
||||
}
|
||||
|
||||
@ -883,6 +891,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
fn sub_types_or_anon(
|
||||
&mut self,
|
||||
sub: Ty<'tcx>,
|
||||
sup: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
if let Err(terr) = self.sub_types(sub, sup, locations) {
|
||||
if let TyKind::Opaque(..) = sup.sty {
|
||||
return self.eq_opaque_type_and_type(sub, sup, locations, category);
|
||||
} else {
|
||||
return Err(terr);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn eq_types(
|
||||
&mut self,
|
||||
a: Ty<'tcx>,
|
||||
@ -919,6 +944,111 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
)
|
||||
}
|
||||
|
||||
fn eq_opaque_type_and_type(
|
||||
&mut self,
|
||||
revealed_ty: Ty<'tcx>,
|
||||
anon_ty: Ty<'tcx>,
|
||||
locations: Locations,
|
||||
category: ConstraintCategory,
|
||||
) -> Fallible<()> {
|
||||
let infcx = self.infcx;
|
||||
let tcx = infcx.tcx;
|
||||
let param_env = self.param_env;
|
||||
let mir_def_id = self.mir_def_id;
|
||||
let opaque_type_map =
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
CustomTypeOp::new(
|
||||
|infcx| {
|
||||
let mut obligations = ObligationAccumulator::default();
|
||||
|
||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
||||
let (output_ty, opaque_type_map) =
|
||||
obligations.add(infcx.instantiate_opaque_types(
|
||||
mir_def_id,
|
||||
dummy_body_id,
|
||||
param_env,
|
||||
&anon_ty,
|
||||
));
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: \
|
||||
instantiated output_ty={:?} \
|
||||
opaque_type_map={:#?} \
|
||||
revealed_ty={:?}",
|
||||
output_ty,
|
||||
opaque_type_map,
|
||||
revealed_ty
|
||||
);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(output_ty, revealed_ty)?,
|
||||
);
|
||||
|
||||
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,
|
||||
);
|
||||
debug!(
|
||||
"eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}",
|
||||
opaque_decl.concrete_ty,
|
||||
opaque_defn_ty
|
||||
);
|
||||
obligations.add(
|
||||
infcx
|
||||
.at(&ObligationCause::dummy(), param_env)
|
||||
.eq(opaque_decl.concrete_ty, opaque_defn_ty)?,
|
||||
);
|
||||
}
|
||||
|
||||
debug!("eq_opaque_type_and_type: equated");
|
||||
|
||||
Ok(InferOk {
|
||||
value: Some(opaque_type_map),
|
||||
obligations: obligations.into_vec(),
|
||||
})
|
||||
},
|
||||
|| "input_output".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let universal_region_relations = match self.universal_region_relations {
|
||||
Some(rel) => rel,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
// Finally, if we instantiated the anon types successfully, we
|
||||
// have to solve any bounds (e.g., `-> impl Iterator` needs to
|
||||
// prove that `T: Iterator` where `T` is the type we
|
||||
// instantiated it with).
|
||||
if let Some(opaque_type_map) = opaque_type_map {
|
||||
for (opaque_def_id, opaque_decl) in opaque_type_map {
|
||||
self.fully_perform_op(
|
||||
locations,
|
||||
category,
|
||||
CustomTypeOp::new(
|
||||
|_cx| {
|
||||
infcx.constrain_opaque_type(
|
||||
opaque_def_id,
|
||||
&opaque_decl,
|
||||
universal_region_relations
|
||||
);
|
||||
Ok(InferOk {
|
||||
value: (),
|
||||
obligations: vec![],
|
||||
})
|
||||
},
|
||||
|| "opaque_type_map".to_string(),
|
||||
),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
self.infcx.tcx
|
||||
}
|
||||
@ -942,7 +1072,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
|
||||
let place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||
let rv_ty = rv.ty(mir, tcx);
|
||||
if let Err(terr) = self.sub_types(
|
||||
if let Err(terr) = self.sub_types_or_anon(
|
||||
rv_ty,
|
||||
place_ty,
|
||||
location.to_locations(),
|
||||
@ -1235,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
||||
|
||||
let locations = term_location.to_locations();
|
||||
|
||||
if let Err(terr) = self.sub_types(
|
||||
if let Err(terr) = self.sub_types_or_anon(
|
||||
sig.output(),
|
||||
dest_ty,
|
||||
locations,
|
||||
@ -2104,6 +2234,7 @@ impl MirPass for TypeckMir {
|
||||
&[],
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
|_| (),
|
||||
);
|
||||
|
||||
@ -2128,3 +2259,21 @@ impl NormalizeLocation for Location {
|
||||
Locations::Single(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ObligationAccumulator<'tcx> {
|
||||
obligations: PredicateObligations<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ObligationAccumulator<'tcx> {
|
||||
fn add<T>(&mut self, value: InferOk<'tcx, T>) -> T {
|
||||
let InferOk { value, obligations } = value;
|
||||
self.obligations.extend(obligations);
|
||||
value
|
||||
}
|
||||
|
||||
fn into_vec(self) -> PredicateObligations<'tcx> {
|
||||
self.obligations
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ nodes within the function.
|
||||
The types of top-level items, which never contain unbound type
|
||||
variables, are stored directly into the `tcx` tables.
|
||||
|
||||
n.b.: A type variable is not the same thing as a type parameter. A
|
||||
N.B.: A type variable is not the same thing as a type parameter. A
|
||||
type variable is rather an "instance" of a type parameter: that is,
|
||||
given a generic function `fn foo<T>(t: T)`: while checking the
|
||||
function `foo`, the type `ty_param(0)` refers to the type `T`, which
|
||||
@ -852,7 +852,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
check_abi(tcx, span, fn_sig.abi());
|
||||
|
||||
// Compute the fty from point of view of inside fn.
|
||||
// Compute the fty from point of view of inside the fn.
|
||||
let fn_sig =
|
||||
tcx.liberate_late_bound_regions(def_id, &fn_sig);
|
||||
let fn_sig =
|
||||
@ -869,10 +869,20 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
|
||||
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
|
||||
|
||||
let revealed_ty = if tcx.features().impl_trait_in_bindings {
|
||||
fcx.require_type_is_sized(expected_type, body.value.span, traits::SizedReturnType);
|
||||
fcx.instantiate_opaque_types_from_value(
|
||||
id,
|
||||
&expected_type
|
||||
)
|
||||
} else {
|
||||
expected_type
|
||||
};
|
||||
|
||||
// Gather locals in statics (because of block expressions).
|
||||
GatherLocalsVisitor { fcx: &fcx, parent_id: id, }.visit_body(body);
|
||||
|
||||
fcx.check_expr_coercable_to_type(&body.value, expected_type);
|
||||
fcx.check_expr_coercable_to_type(&body.value, revealed_ty);
|
||||
|
||||
fcx
|
||||
};
|
||||
@ -957,9 +967,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
|
||||
let o_ty = self.fcx.to_ty(&ty);
|
||||
debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, 1);
|
||||
|
||||
let revealed_ty = self.fcx.instantiate_opaque_types_from_value(
|
||||
self.parent_id,
|
||||
&o_ty);
|
||||
let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
|
||||
self.fcx.instantiate_opaque_types_from_value(
|
||||
self.parent_id,
|
||||
&o_ty
|
||||
)
|
||||
} else {
|
||||
o_ty
|
||||
};
|
||||
|
||||
let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_ty);
|
||||
self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty);
|
||||
@ -1288,90 +1303,96 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
check_packed(tcx, span, def_id);
|
||||
}
|
||||
|
||||
pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
|
||||
debug!("check_item_type(it.id={}, it.name={})",
|
||||
it.id,
|
||||
tcx.item_path_str(tcx.hir.local_def_id(it.id)));
|
||||
pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
|
||||
debug!(
|
||||
"check_item_type(it.id={}, it.name={})",
|
||||
it.id,
|
||||
tcx.item_path_str(tcx.hir.local_def_id(it.id))
|
||||
);
|
||||
let _indenter = indenter();
|
||||
match it.node {
|
||||
// Consts can play a role in type-checking, so they are included here.
|
||||
hir::ItemKind::Static(..) => {
|
||||
let def_id = tcx.hir.local_def_id(it.id);
|
||||
tcx.typeck_tables_of(def_id);
|
||||
maybe_check_static_with_link_section(tcx, def_id, it.span);
|
||||
}
|
||||
hir::ItemKind::Const(..) => {
|
||||
tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
|
||||
}
|
||||
hir::ItemKind::Enum(ref enum_definition, _) => {
|
||||
check_enum(tcx,
|
||||
it.span,
|
||||
&enum_definition.variants,
|
||||
it.id);
|
||||
}
|
||||
hir::ItemKind::Fn(..) => {} // entirely within check_item_body
|
||||
hir::ItemKind::Impl(.., ref impl_item_refs) => {
|
||||
debug!("ItemKind::Impl {} with id {}", it.name, it.id);
|
||||
let impl_def_id = tcx.hir.local_def_id(it.id);
|
||||
if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
|
||||
check_impl_items_against_trait(tcx,
|
||||
it.span,
|
||||
impl_def_id,
|
||||
impl_trait_ref,
|
||||
impl_item_refs);
|
||||
let trait_def_id = impl_trait_ref.def_id;
|
||||
check_on_unimplemented(tcx, trait_def_id, it);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Trait(..) => {
|
||||
let def_id = tcx.hir.local_def_id(it.id);
|
||||
check_on_unimplemented(tcx, def_id, it);
|
||||
}
|
||||
hir::ItemKind::Struct(..) => {
|
||||
check_struct(tcx, it.id, it.span);
|
||||
}
|
||||
hir::ItemKind::Union(..) => {
|
||||
check_union(tcx, it.id, it.span);
|
||||
}
|
||||
hir::ItemKind::Existential(..) |
|
||||
hir::ItemKind::Ty(..) => {
|
||||
let def_id = tcx.hir.local_def_id(it.id);
|
||||
let pty_ty = tcx.type_of(def_id);
|
||||
let generics = tcx.generics_of(def_id);
|
||||
check_bounds_are_used(tcx, &generics, pty_ty);
|
||||
}
|
||||
hir::ItemKind::ForeignMod(ref m) => {
|
||||
check_abi(tcx, it.span, m.abi);
|
||||
// Consts can play a role in type-checking, so they are included here.
|
||||
hir::ItemKind::Static(..) => {
|
||||
let def_id = tcx.hir.local_def_id(it.id);
|
||||
tcx.typeck_tables_of(def_id);
|
||||
maybe_check_static_with_link_section(tcx, def_id, it.span);
|
||||
}
|
||||
hir::ItemKind::Const(..) => {
|
||||
tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
|
||||
}
|
||||
hir::ItemKind::Enum(ref enum_definition, _) => {
|
||||
check_enum(tcx, it.span, &enum_definition.variants, it.id);
|
||||
}
|
||||
hir::ItemKind::Fn(..) => {} // entirely within check_item_body
|
||||
hir::ItemKind::Impl(.., ref impl_item_refs) => {
|
||||
debug!("ItemKind::Impl {} with id {}", it.name, it.id);
|
||||
let impl_def_id = tcx.hir.local_def_id(it.id);
|
||||
if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
|
||||
check_impl_items_against_trait(
|
||||
tcx,
|
||||
it.span,
|
||||
impl_def_id,
|
||||
impl_trait_ref,
|
||||
impl_item_refs,
|
||||
);
|
||||
let trait_def_id = impl_trait_ref.def_id;
|
||||
check_on_unimplemented(tcx, trait_def_id, it);
|
||||
}
|
||||
}
|
||||
hir::ItemKind::Trait(..) => {
|
||||
let def_id = tcx.hir.local_def_id(it.id);
|
||||
check_on_unimplemented(tcx, def_id, it);
|
||||
}
|
||||
hir::ItemKind::Struct(..) => {
|
||||
check_struct(tcx, it.id, it.span);
|
||||
}
|
||||
hir::ItemKind::Union(..) => {
|
||||
check_union(tcx, it.id, it.span);
|
||||
}
|
||||
hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => {
|
||||
let def_id = tcx.hir.local_def_id(it.id);
|
||||
let pty_ty = tcx.type_of(def_id);
|
||||
let generics = tcx.generics_of(def_id);
|
||||
check_bounds_are_used(tcx, &generics, pty_ty);
|
||||
}
|
||||
hir::ItemKind::ForeignMod(ref m) => {
|
||||
check_abi(tcx, it.span, m.abi);
|
||||
|
||||
if m.abi == Abi::RustIntrinsic {
|
||||
for item in &m.items {
|
||||
intrinsic::check_intrinsic_type(tcx, item);
|
||||
}
|
||||
} else if m.abi == Abi::PlatformIntrinsic {
|
||||
for item in &m.items {
|
||||
intrinsic::check_platform_intrinsic_type(tcx, item);
|
||||
}
|
||||
} else {
|
||||
for item in &m.items {
|
||||
let generics = tcx.generics_of(tcx.hir.local_def_id(item.id));
|
||||
if generics.params.len() - generics.own_counts().lifetimes != 0 {
|
||||
let mut err = struct_span_err!(tcx.sess, item.span, E0044,
|
||||
"foreign items may not have type parameters");
|
||||
err.span_label(item.span, "can't have type parameters");
|
||||
// FIXME: once we start storing spans for type arguments, turn this into a
|
||||
// suggestion.
|
||||
err.help("use specialization instead of type parameters by replacing them \
|
||||
with concrete types like `u32`");
|
||||
err.emit();
|
||||
if m.abi == Abi::RustIntrinsic {
|
||||
for item in &m.items {
|
||||
intrinsic::check_intrinsic_type(tcx, item);
|
||||
}
|
||||
} else if m.abi == Abi::PlatformIntrinsic {
|
||||
for item in &m.items {
|
||||
intrinsic::check_platform_intrinsic_type(tcx, item);
|
||||
}
|
||||
} else {
|
||||
for item in &m.items {
|
||||
let generics = tcx.generics_of(tcx.hir.local_def_id(item.id));
|
||||
if generics.params.len() - generics.own_counts().lifetimes != 0 {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
item.span,
|
||||
E0044,
|
||||
"foreign items may not have type parameters"
|
||||
);
|
||||
err.span_label(item.span, "can't have type parameters");
|
||||
// FIXME: once we start storing spans for type arguments, turn this into a
|
||||
// suggestion.
|
||||
err.help(
|
||||
"use specialization instead of type parameters by replacing them \
|
||||
with concrete types like `u32`",
|
||||
);
|
||||
err.emit();
|
||||
}
|
||||
|
||||
if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
|
||||
require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
|
||||
if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
|
||||
require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {/* nothing to do */ }
|
||||
_ => { /* nothing to do */ }
|
||||
}
|
||||
}
|
||||
|
||||
@ -3936,7 +3957,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
hir::ExprKind::Path(ref qpath) => {
|
||||
let (def, opt_ty, segs) = self.resolve_ty_and_def_ufcs(qpath, expr.id, expr.span);
|
||||
debug!("path_foo: {:?} {:?}", def, opt_ty);
|
||||
let ty = if def != Def::Err {
|
||||
self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0
|
||||
} else {
|
||||
|
@ -494,7 +494,7 @@ declare_features! (
|
||||
// Allows `Self` in type definitions
|
||||
(active, self_in_typedefs, "1.30.0", Some(49303), None),
|
||||
|
||||
// unsized rvalues at arguments and parameters
|
||||
// Allows unsized rvalues at arguments and parameters
|
||||
(active, unsized_locals, "1.30.0", Some(48055), None),
|
||||
|
||||
// #![test_runner]
|
||||
@ -505,13 +505,16 @@ declare_features! (
|
||||
(active, custom_inner_attributes, "1.30.0", Some(38356), None),
|
||||
|
||||
// Self struct constructor (RFC 2302)
|
||||
(active, self_struct_ctor, "1.31.0", Some(51994), None),
|
||||
(active, self_struct_ctor, "1.30.0", Some(51994), None),
|
||||
|
||||
// allow mixing of bind-by-move in patterns and references to
|
||||
// those identifiers in guards, *if* we are using MIR-borrowck
|
||||
// (aka NLL). Essentially this means you need to be on
|
||||
// edition:2018 or later.
|
||||
(active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
|
||||
|
||||
// Allows `impl Trait` in bindings (`let`, `const`, `static`)
|
||||
(active, impl_trait_in_bindings, "1.30.0", Some(34511), None),
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
@ -0,0 +1,17 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
const FOO: impl Copy = 42;
|
||||
|
||||
static BAR: impl Copy = 42;
|
||||
|
||||
fn main() {
|
||||
let foo = impl Copy = 42;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
error: expected expression, found keyword `impl`
|
||||
--> $DIR/feature-gate-impl_trait_in_bindings.rs:16:15
|
||||
|
|
||||
LL | let foo = impl Copy = 42;
|
||||
| ^^^^ expected expression
|
||||
|
||||
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
|
||||
--> $DIR/feature-gate-impl_trait_in_bindings.rs:11:12
|
||||
|
|
||||
LL | const FOO: impl Copy = 42;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
|
||||
--> $DIR/feature-gate-impl_trait_in_bindings.rs:13:13
|
||||
|
|
||||
LL | static BAR: impl Copy = 42;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0562`.
|
@ -1,5 +1,5 @@
|
||||
error[E0411]: cannot find type `Self` in this scope
|
||||
--> $DIR/feature-gate-self-in-typedefs.rs:13:17
|
||||
--> $DIR/feature-gate-self_in_typedefs.rs:13:17
|
||||
|
|
||||
LL | Cons(T, &'a Self)
|
||||
| ^^^^ `Self` is only available in traits and impls
|
Loading…
Reference in New Issue
Block a user