Skip to content

Fix leak of skolemized types in HRTB #19438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,17 @@ impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
}
}

pub fn collect_regions<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> Vec<ty::Region>
where T : TypeFoldable<'tcx>
{
let mut vec = Vec::new();
{
let mut folder = RegionFolder::new(tcx, |r, _| { vec.push(r); r });
value.fold_with(&mut folder);
}
vec
}

impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx }

Expand Down
41 changes: 18 additions & 23 deletions src/librustc/middle/typeck/check/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use middle::subst::{Subst, Substs};
use middle::ty::{mod, Ty};
use middle::typeck::check::{check_expr, check_expr_has_type, demand, FnCtxt};
use middle::typeck::check::{instantiate_path, structurally_resolved_type, valid_range_bounds};
use middle::typeck::infer::{mod, resolve};
use middle::typeck::infer;
use middle::typeck::require_same_types;
use util::nodemap::FnvHashMap;

Expand Down Expand Up @@ -142,11 +142,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
ast::PatRegion(ref inner) => {
let inner_ty = fcx.infcx().next_ty_var();

let mutbl = infer::resolve_type(
fcx.infcx(), Some(pat.span),
expected, resolve::try_resolve_tvar_shallow)
.ok()
.and_then(|t| ty::deref(t, true))
let mutbl =
ty::deref(fcx.infcx().shallow_resolve(expected), true)
.map_or(ast::MutImmutable, |mt| mt.mutbl);

let mt = ty::mt { ty: inner_ty, mutbl: mutbl };
Expand Down Expand Up @@ -213,23 +210,21 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
inner: &ast::Pat) -> bool {
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
match infer::resolve_type(
fcx.infcx(), Some(span),
expected, resolve::try_resolve_tvar_shallow) {
Ok(t) if pat_is_binding(&tcx.def_map, inner) => {
ty::deref(t, true).map_or(true, |mt| match mt.ty.sty {
ty::ty_trait(_) => {
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
span_err!(tcx.sess, span, E0033,
"type `{}` cannot be dereferenced",
fcx.infcx().ty_to_string(t));
false
}
_ => true
})
}
_ => true
if pat_is_binding(&tcx.def_map, inner) {
let expected = fcx.infcx().shallow_resolve(expected);
ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty {
ty::ty_trait(_) => {
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
span_err!(tcx.sess, span, E0033,
"type `{}` cannot be dereferenced",
fcx.infcx().ty_to_string(expected));
false
}
_ => true
})
} else {
true
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/typeck/check/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
debug!("found object type {}", kind);

let arg_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 0);
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(arg_param_ty);
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
debug!("arg_param_ty {}", arg_param_ty.repr(tcx));

let input_tys = match arg_param_ty.sty {
Expand All @@ -209,7 +209,7 @@ fn deduce_unboxed_closure_expectations_from_trait_ref<'a,'tcx>(
debug!("input_tys {}", input_tys.repr(tcx));

let ret_param_ty = *trait_ref.substs.types.get(subst::TypeSpace, 1);
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(ret_param_ty);
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
debug!("ret_param_ty {}", ret_param_ty.repr(tcx));

let fn_sig = ty::FnSig {
Expand Down
9 changes: 1 addition & 8 deletions src/librustc/middle/typeck/check/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
use middle::ty::{mod, Ty};
use middle::typeck::check::FnCtxt;
use middle::typeck::infer;
use middle::typeck::infer::resolve_type;
use middle::typeck::infer::resolve::try_resolve_tvar_shallow;

use std::result::{Err, Ok};
use std::result;
Expand Down Expand Up @@ -68,12 +66,7 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
debug!("demand::coerce(expected = {}, expr_ty = {})",
expected.repr(fcx.ccx.tcx),
expr_ty.repr(fcx.ccx.tcx));
let expected = if ty::type_needs_infer(expected) {
resolve_type(fcx.infcx(),
None,
expected,
try_resolve_tvar_shallow).unwrap_or(expected)
} else { expected };
let expected = fcx.infcx().resolve_type_vars_if_possible(&expected);
match fcx.mk_assignty(expr, expr_ty, expected) {
result::Ok(()) => { /* ok */ }
result::Err(ref err) => {
Expand Down
16 changes: 5 additions & 11 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1382,13 +1382,7 @@ fn check_cast(fcx: &FnCtxt,
let t_1 = fcx.to_ty(t);
let t_1 = structurally_resolved_type(fcx, span, t_1);

if ty::type_is_scalar(t_1) {
// Supply the type as a hint so as to influence integer
// literals and other things that might care.
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1))
} else {
check_expr(fcx, e)
}
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));

let t_e = fcx.expr_ty(e);

Expand Down Expand Up @@ -1626,7 +1620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

pub fn default_diverging_type_variables_to_nil(&self) {
for (_, &ref ty) in self.inh.node_types.borrow_mut().iter_mut() {
if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(*ty)) {
if self.infcx().type_var_diverges(self.infcx().resolve_type_vars_if_possible(ty)) {
demand::eqtype(self, codemap::DUMMY_SP, *ty, ty::mk_nil(self.tcx()));
}
}
Expand Down Expand Up @@ -2563,7 +2557,7 @@ fn lookup_method_for_for_loop<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
let method_type = match method {
Some(ref method) => method.ty,
None => {
let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(expr_type);
let true_expr_type = fcx.infcx().resolve_type_vars_if_possible(&expr_type);

if !ty::type_is_error(true_expr_type) {
let ty_string = fcx.infcx().ty_to_string(true_expr_type);
Expand Down Expand Up @@ -4468,11 +4462,11 @@ impl<'tcx> Expectation<'tcx> {
}
ExpectCastableToType(t) => {
ExpectCastableToType(
fcx.infcx().resolve_type_vars_if_possible(t))
fcx.infcx().resolve_type_vars_if_possible(&t))
}
ExpectHasType(t) => {
ExpectHasType(
fcx.infcx().resolve_type_vars_if_possible(t))
fcx.infcx().resolve_type_vars_if_possible(&t))
}
}
}
Expand Down
8 changes: 1 addition & 7 deletions src/librustc/middle/typeck/check/regionck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,6 @@ use middle::typeck::astconv::AstConv;
use middle::typeck::check::FnCtxt;
use middle::typeck::check::regionmanip;
use middle::typeck::check::vtable;
use middle::typeck::infer::resolve_and_force_all_but_regions;
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::MethodCall;
use middle::pat_util;
Expand Down Expand Up @@ -295,11 +293,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
/// of b will be `&<R0>.int` and then `*b` will require that `<R0>` be bigger than the let and
/// the `*b` expression, so we will effectively resolve `<R0>` to be the block B.
pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> {
match resolve_type(self.fcx.infcx(), None, unresolved_ty,
resolve_and_force_all_but_regions) {
Ok(t) => t,
Err(_) => ty::mk_err()
}
self.fcx.infcx().resolve_type_vars_if_possible(&unresolved_ty)
}

/// Try to resolve the type for the given node.
Expand Down
6 changes: 2 additions & 4 deletions src/librustc/middle/typeck/check/vtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,7 @@ fn resolve_trait_ref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, obligation: &Obligation<'
-> (Rc<ty::TraitRef<'tcx>>, Ty<'tcx>)
{
let trait_ref =
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
&*obligation.trait_ref);
fcx.infcx().resolve_type_vars_if_possible(&*obligation.trait_ref);
let self_ty =
trait_ref.substs.self_ty().unwrap();
(Rc::new(trait_ref), self_ty)
Expand Down Expand Up @@ -371,8 +370,7 @@ pub fn report_selection_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
OutputTypeParameterMismatch(ref expected_trait_ref, ref e) => {
let expected_trait_ref =
fcx.infcx().resolve_type_vars_in_trait_ref_if_possible(
&**expected_trait_ref);
fcx.infcx().resolve_type_vars_if_possible(&**expected_trait_ref);
let (trait_ref, self_ty) = resolve_trait_ref(fcx, obligation);
if !ty::type_is_error(self_ty) {
fcx.tcx().sess.span_err(
Expand Down
29 changes: 6 additions & 23 deletions src/librustc/middle/typeck/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ use middle::ty::{mod, Ty};
use middle::ty_fold::{TypeFolder,TypeFoldable};
use middle::typeck::astconv::AstConv;
use middle::typeck::check::FnCtxt;
use middle::typeck::infer::{force_all, resolve_all, resolve_region};
use middle::typeck::infer::resolve_type;
use middle::typeck::infer;
use middle::typeck::{MethodCall, MethodCallee};
use middle::typeck::write_substs_to_tcx;
Expand Down Expand Up @@ -339,8 +337,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}

fn resolve<T:ResolveIn<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
t.resolve_in(&mut Resolver::new(self.fcx, reason))
fn resolve<T:TypeFoldable<'tcx>>(&self, t: &T, reason: ResolveReason) -> T {
t.fold_with(&mut Resolver::new(self.fcx, reason))
}
}

Expand Down Expand Up @@ -375,19 +373,6 @@ impl ResolveReason {
}
}

///////////////////////////////////////////////////////////////////////////
// Convenience methods for resolving different kinds of things.

trait ResolveIn<'tcx> {
fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> Self;
}

impl<'tcx, T: TypeFoldable<'tcx>> ResolveIn<'tcx> for T {
fn resolve_in<'a>(&self, resolver: &mut Resolver<'a, 'tcx>) -> T {
self.fold_with(resolver)
}
}

///////////////////////////////////////////////////////////////////////////
// The Resolver. This is the type folding engine that detects
// unresolved types and so forth.
Expand Down Expand Up @@ -465,21 +450,19 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Resolver<'cx, 'tcx> {
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !ty::type_needs_infer(t) {
return t;
}

match resolve_type(self.infcx, None, t, resolve_all | force_all) {
match self.infcx.fully_resolve(&t) {
Ok(t) => t,
Err(e) => {
debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
t.repr(self.tcx));
self.report_error(e);
ty::mk_err()
}
}
}

fn fold_region(&mut self, r: ty::Region) -> ty::Region {
match resolve_region(self.infcx, r, resolve_all | force_all) {
match self.infcx.fully_resolve(&r) {
Ok(r) => r,
Err(e) => {
self.report_error(e);
Expand Down
86 changes: 20 additions & 66 deletions src/librustc/middle/typeck/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,12 @@ use middle::ty::{ty_param, Polytype, ty_ptr};
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
use middle::ty::{ty_closure};
use middle::ty::type_is_ty_var;
use middle::subst::Subst;
use middle::ty;
use middle::typeck::CrateCtxt;
use middle::typeck::infer::combine::Combine;
use middle::typeck::infer::InferCtxt;
use middle::typeck::infer::{new_infer_ctxt, resolve_ivar, resolve_type};
use middle::typeck::infer::new_infer_ctxt;
use std::collections::{HashSet};
use std::cell::RefCell;
use std::rc::Rc;
Expand All @@ -54,80 +53,35 @@ use util::ppaux::Repr;
mod orphan;
mod overlap;

fn get_base_type<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
span: Span,
original_type: Ty<'tcx>)
-> Option<Ty<'tcx>> {
let resolved_type = match resolve_type(inference_context,
Some(span),
original_type,
resolve_ivar) {
Ok(resulting_type) if !type_is_ty_var(resulting_type) => resulting_type,
_ => {
inference_context.tcx.sess.span_fatal(span,
"the type of this value must be known in order \
to determine the base type");
}
};

match resolved_type.sty {
ty_enum(..) | ty_struct(..) | ty_unboxed_closure(..) => {
debug!("(getting base type) found base type");
Some(resolved_type)
// Returns the def ID of the base type, if there is one.
fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
span: Span,
ty: Ty<'tcx>)
-> Option<DefId> {
match ty.sty {
ty_enum(def_id, _) |
ty_struct(def_id, _) => {
Some(def_id)
}

_ if ty::type_is_trait(resolved_type) => {
debug!("(getting base type) found base type (trait)");
Some(resolved_type)
ty_trait(ref t) => {
Some(t.principal.def_id)
}

ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
ty_ptr(_) | ty_rptr(_, _) => {
debug!("(getting base type) no base type; found {}",
original_type.sty);
None
}
ty_trait(..) => panic!("should have been caught")
}
}

// Returns the def ID of the base type, if there is one.
fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>,
span: Span,
original_type: Ty<'tcx>)
-> Option<DefId> {
match get_base_type(inference_context, span, original_type) {
None => None,
Some(base_type) => {
match base_type.sty {
ty_enum(def_id, _) |
ty_struct(def_id, _) |
ty_unboxed_closure(def_id, _, _) => {
Some(def_id)
}
ty_ptr(ty::mt {ty, ..}) |
ty_rptr(_, ty::mt {ty, ..}) |
ty_uniq(ty) => {
match ty.sty {
ty_trait(box ty::TyTrait { ref principal, .. }) => {
Some(principal.def_id)
}
_ => {
panic!("get_base_type() returned a type that wasn't an \
enum, struct, or trait");
}
}
}
ty_trait(box ty::TyTrait { ref principal, .. }) => {
Some(principal.def_id)
}
_ => {
panic!("get_base_type() returned a type that wasn't an \
enum, struct, or trait");
}
}
ty_infer(..) | ty_unboxed_closure(..) => {
// `ty` comes from a user declaration so we should only expect types
// that the user can type
inference_context.tcx.sess.span_bug(
span,
format!("coherence encountered unexpected type searching for base type: {}",
ty.repr(inference_context.tcx))[]);
}
}
}
Expand Down
Loading