Handle impl trait in MIR type checked for assignments.

This commit is contained in:
Matthew Jasper 2018-09-08 07:52:03 +01:00 committed by Alexander Regueiro
parent cf915849f0
commit 218189536d
11 changed files with 368 additions and 235 deletions

View File

@ -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> {

View File

@ -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)))

View File

@ -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(_)) =>

View File

@ -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
}
}

View File

@ -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>(
&region_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
}
}

View File

@ -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 {

View File

@ -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! (

View File

@ -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;
}

View File

@ -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`.

View File

@ -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