Skip to content

Commit

Permalink
Handle impl trait in MIR type checked for assignments.
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewjasper authored and Alexander Regueiro committed Sep 25, 2018
1 parent cf91584 commit 2181895
Show file tree
Hide file tree
Showing 11 changed files with 368 additions and 235 deletions.
5 changes: 2 additions & 3 deletions src/librustc/diagnostics.rs
Expand Up @@ -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:
Expand All @@ -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> {
Expand Down
57 changes: 49 additions & 8 deletions src/librustc/hir/lowering.rs
Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 }],
}
}
Expand Down Expand Up @@ -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)))
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/relate.rs
Expand Up @@ -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(_)) =>
Expand Down
147 changes: 15 additions & 132 deletions src/librustc_mir/borrow_check/nll/type_check/input_output.rs
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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
}
}

0 comments on commit 2181895

Please sign in to comment.