mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +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##"
|
E0562: r##"
|
||||||
Abstract return types (written `impl Trait` for some trait `Trait`) are only
|
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:
|
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
|
Make sure `impl Trait` only appears in return-type position.
|
||||||
binding.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
fn count_to_n(n: usize) -> impl Iterator<Item=usize> {
|
fn count_to_n(n: usize) -> impl Iterator<Item=usize> {
|
||||||
|
@ -1284,12 +1284,18 @@ impl<'a> LoweringContext<'a> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
ImplTraitContext::Disallowed => {
|
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!(
|
span_err!(
|
||||||
self.sess,
|
self.sess,
|
||||||
t.span,
|
t.span,
|
||||||
E0562,
|
E0562,
|
||||||
"`impl Trait` not allowed outside of function \
|
"`impl Trait` not allowed outside of {}",
|
||||||
and inherent method return types or bindings"
|
allowed_in,
|
||||||
);
|
);
|
||||||
hir::TyKind::Err
|
hir::TyKind::Err
|
||||||
}
|
}
|
||||||
@ -2206,8 +2212,10 @@ impl<'a> LoweringContext<'a> {
|
|||||||
let impl_trait_ty = self.lower_existential_impl_trait(
|
let impl_trait_ty = self.lower_existential_impl_trait(
|
||||||
span, Some(fn_def_id), return_impl_trait_id, |this| {
|
span, Some(fn_def_id), return_impl_trait_id, |this| {
|
||||||
let output_ty = match output {
|
let output_ty = match output {
|
||||||
FunctionRetTy::Ty(ty) =>
|
FunctionRetTy::Ty(ty) => {
|
||||||
this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))),
|
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) => {
|
FunctionRetTy::Default(span) => {
|
||||||
let LoweredNodeId { node_id, hir_id } = this.next_id();
|
let LoweredNodeId { node_id, hir_id } = this.next_id();
|
||||||
P(hir::Ty {
|
P(hir::Ty {
|
||||||
@ -2702,14 +2710,31 @@ impl<'a> LoweringContext<'a> {
|
|||||||
ItemKind::Static(ref t, m, ref e) => {
|
ItemKind::Static(ref t, m, ref e) => {
|
||||||
let value = self.lower_body(None, |this| this.lower_expr(e));
|
let value = self.lower_body(None, |this| this.lower_expr(e));
|
||||||
hir::ItemKind::Static(
|
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),
|
self.lower_mutability(m),
|
||||||
value,
|
value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ItemKind::Const(ref t, ref e) => {
|
ItemKind::Const(ref t, ref e) => {
|
||||||
let value = self.lower_body(None, |this| this.lower_expr(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) => {
|
ItemKind::Fn(ref decl, header, ref generics, ref body) => {
|
||||||
let fn_def_id = self.resolver.definitions().local_def_id(id);
|
let fn_def_id = self.resolver.definitions().local_def_id(id);
|
||||||
@ -3258,6 +3283,22 @@ impl<'a> LoweringContext<'a> {
|
|||||||
}
|
}
|
||||||
ids
|
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 }],
|
_ => smallvec![hir::ItemId { id: i.id }],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3817,8 +3858,8 @@ impl<'a> LoweringContext<'a> {
|
|||||||
}
|
}
|
||||||
ExprKind::Block(ref blk, opt_label) => {
|
ExprKind::Block(ref blk, opt_label) => {
|
||||||
hir::ExprKind::Block(self.lower_block(blk,
|
hir::ExprKind::Block(self.lower_block(blk,
|
||||||
opt_label.is_some()),
|
opt_label.is_some()),
|
||||||
self.lower_label(opt_label))
|
self.lower_label(opt_label))
|
||||||
}
|
}
|
||||||
ExprKind::Assign(ref el, ref er) => {
|
ExprKind::Assign(ref el, ref er) => {
|
||||||
hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(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 tcx = relation.tcx();
|
||||||
let a_sty = &a.sty;
|
let a_sty = &a.sty;
|
||||||
let b_sty = &b.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) {
|
match (a_sty, b_sty) {
|
||||||
(&ty::Infer(_), _) |
|
(&ty::Infer(_), _) |
|
||||||
(_, &ty::Infer(_)) =>
|
(_, &ty::Infer(_)) =>
|
||||||
|
@ -17,15 +17,8 @@
|
|||||||
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
|
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
|
||||||
//! contain revealed `impl Trait` values).
|
//! 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 borrow_check::nll::universal_regions::UniversalRegions;
|
||||||
use rustc::hir::def_id::DefId;
|
|
||||||
use rustc::infer::InferOk;
|
|
||||||
use rustc::mir::*;
|
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::ty::Ty;
|
||||||
|
|
||||||
use rustc_data_structures::indexed_vec::Idx;
|
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(
|
pub(super) fn equate_inputs_and_outputs(
|
||||||
&mut self,
|
&mut self,
|
||||||
mir: &Mir<'tcx>,
|
mir: &Mir<'tcx>,
|
||||||
mir_def_id: DefId,
|
|
||||||
universal_regions: &UniversalRegions<'tcx>,
|
universal_regions: &UniversalRegions<'tcx>,
|
||||||
universal_region_relations: &UniversalRegionRelations<'tcx>,
|
|
||||||
normalized_inputs_and_output: &[Ty<'tcx>],
|
normalized_inputs_and_output: &[Ty<'tcx>],
|
||||||
) {
|
) {
|
||||||
let tcx = self.infcx.tcx;
|
|
||||||
|
|
||||||
let (&normalized_output_ty, normalized_input_tys) =
|
let (&normalized_output_ty, normalized_input_tys) =
|
||||||
normalized_inputs_and_output.split_last().unwrap();
|
normalized_inputs_and_output.split_last().unwrap();
|
||||||
let infcx = self.infcx;
|
|
||||||
|
|
||||||
// Equate expected input tys with those in the MIR.
|
// Equate expected input tys with those in the MIR.
|
||||||
let argument_locals = (1..).map(Local::new);
|
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`
|
// Return types are a bit more complex. They may contain existential `impl Trait`
|
||||||
// types.
|
// types.
|
||||||
let param_env = self.param_env;
|
|
||||||
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
|
let mir_output_ty = mir.local_decls[RETURN_PLACE].ty;
|
||||||
let output_span = mir.local_decls[RETURN_PLACE].source_info.span;
|
let output_span = mir.local_decls[RETURN_PLACE].source_info.span;
|
||||||
let opaque_type_map =
|
if let Err(terr) = self.eq_opaque_type_and_type(
|
||||||
self.fully_perform_op(
|
mir_output_ty,
|
||||||
Locations::All(output_span),
|
normalized_output_ty,
|
||||||
ConstraintCategory::BoringNoLocation,
|
Locations::All(output_span),
|
||||||
CustomTypeOp::new(
|
ConstraintCategory::BoringNoLocation,
|
||||||
|infcx| {
|
) {
|
||||||
let mut obligations = ObligationAccumulator::default();
|
span_mirbug!(
|
||||||
|
self,
|
||||||
let dummy_body_id = ObligationCause::dummy().body_id;
|
Location::START,
|
||||||
let (output_ty, opaque_type_map) =
|
"equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`",
|
||||||
obligations.add(infcx.instantiate_opaque_types(
|
normalized_output_ty,
|
||||||
mir_def_id,
|
mir_output_ty,
|
||||||
dummy_body_id,
|
terr
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
|
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::universal_regions::UniversalRegions;
|
||||||
use borrow_check::nll::ToRegionVid;
|
use borrow_check::nll::ToRegionVid;
|
||||||
|
use borrow_check::nll::renumber;
|
||||||
use dataflow::move_paths::MoveData;
|
use dataflow::move_paths::MoveData;
|
||||||
use dataflow::FlowAtLocation;
|
use dataflow::FlowAtLocation;
|
||||||
use dataflow::MaybeInitializedPlaces;
|
use dataflow::MaybeInitializedPlaces;
|
||||||
@ -29,15 +30,18 @@ use rustc::hir;
|
|||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::infer::canonical::QueryRegionConstraint;
|
use rustc::infer::canonical::QueryRegionConstraint;
|
||||||
use rustc::infer::region_constraints::GenericKind;
|
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::interpret::EvalErrorKind::BoundsCheck;
|
||||||
use rustc::mir::tcx::PlaceTy;
|
use rustc::mir::tcx::PlaceTy;
|
||||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||||
use rustc::mir::*;
|
use rustc::mir::*;
|
||||||
|
use rustc::traits::{ObligationCause, PredicateObligations};
|
||||||
use rustc::traits::query::type_op;
|
use rustc::traits::query::type_op;
|
||||||
|
use rustc::traits::query::type_op::custom::CustomTypeOp;
|
||||||
use rustc::traits::query::{Fallible, NoSolution};
|
use rustc::traits::query::{Fallible, NoSolution};
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind};
|
||||||
|
use rustc::ty::subst::Subst;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use syntax_pos::{Span, DUMMY_SP};
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
@ -155,12 +159,11 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
|||||||
®ion_bound_pairs,
|
®ion_bound_pairs,
|
||||||
Some(implicit_region_bound),
|
Some(implicit_region_bound),
|
||||||
Some(&mut borrowck_context),
|
Some(&mut borrowck_context),
|
||||||
|
Some(&universal_region_relations),
|
||||||
|cx| {
|
|cx| {
|
||||||
cx.equate_inputs_and_outputs(
|
cx.equate_inputs_and_outputs(
|
||||||
mir,
|
mir,
|
||||||
mir_def_id,
|
|
||||||
universal_regions,
|
universal_regions,
|
||||||
&universal_region_relations,
|
|
||||||
&normalized_inputs_and_output,
|
&normalized_inputs_and_output,
|
||||||
);
|
);
|
||||||
liveness::generate(cx, mir, elements, flow_inits, move_data);
|
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>)],
|
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, '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,
|
mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R,
|
||||||
) -> R where {
|
) -> R where {
|
||||||
let mut checker = TypeChecker::new(
|
let mut checker = TypeChecker::new(
|
||||||
@ -192,6 +196,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>(
|
|||||||
region_bound_pairs,
|
region_bound_pairs,
|
||||||
implicit_region_bound,
|
implicit_region_bound,
|
||||||
borrowck_context,
|
borrowck_context,
|
||||||
|
universal_region_relations,
|
||||||
);
|
);
|
||||||
let errors_reported = {
|
let errors_reported = {
|
||||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
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>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||||
|
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BorrowCheckContext<'a, 'tcx: 'a> {
|
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>)],
|
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||||
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>,
|
||||||
|
universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
TypeChecker {
|
TypeChecker {
|
||||||
infcx,
|
infcx,
|
||||||
@ -810,6 +817,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||||||
implicit_region_bound,
|
implicit_region_bound,
|
||||||
borrowck_context,
|
borrowck_context,
|
||||||
reported_errors: FxHashSet(),
|
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(
|
fn eq_types(
|
||||||
&mut self,
|
&mut self,
|
||||||
a: Ty<'tcx>,
|
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> {
|
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
self.infcx.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 place_ty = place.ty(mir, tcx).to_ty(tcx);
|
||||||
let rv_ty = rv.ty(mir, 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,
|
rv_ty,
|
||||||
place_ty,
|
place_ty,
|
||||||
location.to_locations(),
|
location.to_locations(),
|
||||||
@ -1235,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||||||
|
|
||||||
let locations = term_location.to_locations();
|
let locations = term_location.to_locations();
|
||||||
|
|
||||||
if let Err(terr) = self.sub_types(
|
if let Err(terr) = self.sub_types_or_anon(
|
||||||
sig.output(),
|
sig.output(),
|
||||||
dest_ty,
|
dest_ty,
|
||||||
locations,
|
locations,
|
||||||
@ -2104,6 +2234,7 @@ impl MirPass for TypeckMir {
|
|||||||
&[],
|
&[],
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
|_| (),
|
|_| (),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -2128,3 +2259,21 @@ impl NormalizeLocation for Location {
|
|||||||
Locations::Single(self)
|
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
|
The types of top-level items, which never contain unbound type
|
||||||
variables, are stored directly into the `tcx` tables.
|
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,
|
type variable is rather an "instance" of a type parameter: that is,
|
||||||
given a generic function `fn foo<T>(t: T)`: while checking the
|
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
|
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());
|
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 =
|
let fn_sig =
|
||||||
tcx.liberate_late_bound_regions(def_id, &fn_sig);
|
tcx.liberate_late_bound_regions(def_id, &fn_sig);
|
||||||
let 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);
|
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);
|
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).
|
// Gather locals in statics (because of block expressions).
|
||||||
GatherLocalsVisitor { fcx: &fcx, parent_id: id, }.visit_body(body);
|
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
|
fcx
|
||||||
};
|
};
|
||||||
@ -957,9 +967,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
|
|||||||
let o_ty = self.fcx.to_ty(&ty);
|
let o_ty = self.fcx.to_ty(&ty);
|
||||||
debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, 1);
|
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(
|
let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings {
|
||||||
self.parent_id,
|
self.fcx.instantiate_opaque_types_from_value(
|
||||||
&o_ty);
|
self.parent_id,
|
||||||
|
&o_ty
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
o_ty
|
||||||
|
};
|
||||||
|
|
||||||
let c_ty = self.fcx.inh.infcx.canonicalize_response(&revealed_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);
|
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);
|
check_packed(tcx, span, def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
|
pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
|
||||||
debug!("check_item_type(it.id={}, it.name={})",
|
debug!(
|
||||||
it.id,
|
"check_item_type(it.id={}, it.name={})",
|
||||||
tcx.item_path_str(tcx.hir.local_def_id(it.id)));
|
it.id,
|
||||||
|
tcx.item_path_str(tcx.hir.local_def_id(it.id))
|
||||||
|
);
|
||||||
let _indenter = indenter();
|
let _indenter = indenter();
|
||||||
match it.node {
|
match it.node {
|
||||||
// Consts can play a role in type-checking, so they are included here.
|
// Consts can play a role in type-checking, so they are included here.
|
||||||
hir::ItemKind::Static(..) => {
|
hir::ItemKind::Static(..) => {
|
||||||
let def_id = tcx.hir.local_def_id(it.id);
|
let def_id = tcx.hir.local_def_id(it.id);
|
||||||
tcx.typeck_tables_of(def_id);
|
tcx.typeck_tables_of(def_id);
|
||||||
maybe_check_static_with_link_section(tcx, def_id, it.span);
|
maybe_check_static_with_link_section(tcx, def_id, it.span);
|
||||||
}
|
}
|
||||||
hir::ItemKind::Const(..) => {
|
hir::ItemKind::Const(..) => {
|
||||||
tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
|
tcx.typeck_tables_of(tcx.hir.local_def_id(it.id));
|
||||||
}
|
}
|
||||||
hir::ItemKind::Enum(ref enum_definition, _) => {
|
hir::ItemKind::Enum(ref enum_definition, _) => {
|
||||||
check_enum(tcx,
|
check_enum(tcx, it.span, &enum_definition.variants, it.id);
|
||||||
it.span,
|
}
|
||||||
&enum_definition.variants,
|
hir::ItemKind::Fn(..) => {} // entirely within check_item_body
|
||||||
it.id);
|
hir::ItemKind::Impl(.., ref impl_item_refs) => {
|
||||||
}
|
debug!("ItemKind::Impl {} with id {}", it.name, it.id);
|
||||||
hir::ItemKind::Fn(..) => {} // entirely within check_item_body
|
let impl_def_id = tcx.hir.local_def_id(it.id);
|
||||||
hir::ItemKind::Impl(.., ref impl_item_refs) => {
|
if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
|
||||||
debug!("ItemKind::Impl {} with id {}", it.name, it.id);
|
check_impl_items_against_trait(
|
||||||
let impl_def_id = tcx.hir.local_def_id(it.id);
|
tcx,
|
||||||
if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
|
it.span,
|
||||||
check_impl_items_against_trait(tcx,
|
impl_def_id,
|
||||||
it.span,
|
impl_trait_ref,
|
||||||
impl_def_id,
|
impl_item_refs,
|
||||||
impl_trait_ref,
|
);
|
||||||
impl_item_refs);
|
let trait_def_id = impl_trait_ref.def_id;
|
||||||
let trait_def_id = impl_trait_ref.def_id;
|
check_on_unimplemented(tcx, trait_def_id, it);
|
||||||
check_on_unimplemented(tcx, trait_def_id, it);
|
}
|
||||||
}
|
}
|
||||||
}
|
hir::ItemKind::Trait(..) => {
|
||||||
hir::ItemKind::Trait(..) => {
|
let def_id = tcx.hir.local_def_id(it.id);
|
||||||
let def_id = tcx.hir.local_def_id(it.id);
|
check_on_unimplemented(tcx, def_id, it);
|
||||||
check_on_unimplemented(tcx, def_id, it);
|
}
|
||||||
}
|
hir::ItemKind::Struct(..) => {
|
||||||
hir::ItemKind::Struct(..) => {
|
check_struct(tcx, it.id, it.span);
|
||||||
check_struct(tcx, it.id, it.span);
|
}
|
||||||
}
|
hir::ItemKind::Union(..) => {
|
||||||
hir::ItemKind::Union(..) => {
|
check_union(tcx, it.id, it.span);
|
||||||
check_union(tcx, it.id, it.span);
|
}
|
||||||
}
|
hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => {
|
||||||
hir::ItemKind::Existential(..) |
|
let def_id = tcx.hir.local_def_id(it.id);
|
||||||
hir::ItemKind::Ty(..) => {
|
let pty_ty = tcx.type_of(def_id);
|
||||||
let def_id = tcx.hir.local_def_id(it.id);
|
let generics = tcx.generics_of(def_id);
|
||||||
let pty_ty = tcx.type_of(def_id);
|
check_bounds_are_used(tcx, &generics, pty_ty);
|
||||||
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);
|
||||||
hir::ItemKind::ForeignMod(ref m) => {
|
|
||||||
check_abi(tcx, it.span, m.abi);
|
|
||||||
|
|
||||||
if m.abi == Abi::RustIntrinsic {
|
if m.abi == Abi::RustIntrinsic {
|
||||||
for item in &m.items {
|
for item in &m.items {
|
||||||
intrinsic::check_intrinsic_type(tcx, item);
|
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();
|
|
||||||
}
|
}
|
||||||
|
} 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 {
|
if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node {
|
||||||
require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
|
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) => {
|
hir::ExprKind::Path(ref qpath) => {
|
||||||
let (def, opt_ty, segs) = self.resolve_ty_and_def_ufcs(qpath, expr.id, expr.span);
|
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 {
|
let ty = if def != Def::Err {
|
||||||
self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0
|
self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0
|
||||||
} else {
|
} else {
|
||||||
|
@ -494,7 +494,7 @@ declare_features! (
|
|||||||
// Allows `Self` in type definitions
|
// Allows `Self` in type definitions
|
||||||
(active, self_in_typedefs, "1.30.0", Some(49303), None),
|
(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),
|
(active, unsized_locals, "1.30.0", Some(48055), None),
|
||||||
|
|
||||||
// #![test_runner]
|
// #![test_runner]
|
||||||
@ -505,13 +505,16 @@ declare_features! (
|
|||||||
(active, custom_inner_attributes, "1.30.0", Some(38356), None),
|
(active, custom_inner_attributes, "1.30.0", Some(38356), None),
|
||||||
|
|
||||||
// Self struct constructor (RFC 2302)
|
// 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
|
// allow mixing of bind-by-move in patterns and references to
|
||||||
// those identifiers in guards, *if* we are using MIR-borrowck
|
// those identifiers in guards, *if* we are using MIR-borrowck
|
||||||
// (aka NLL). Essentially this means you need to be on
|
// (aka NLL). Essentially this means you need to be on
|
||||||
// edition:2018 or later.
|
// edition:2018 or later.
|
||||||
(active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
|
(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! (
|
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
|
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)
|
LL | Cons(T, &'a Self)
|
||||||
| ^^^^ `Self` is only available in traits and impls
|
| ^^^^ `Self` is only available in traits and impls
|
Loading…
Reference in New Issue
Block a user