Skip to content

Fix various ICEs relating to trans'ing fields with associated types #20706

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

Merged
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
5 changes: 1 addition & 4 deletions src/librustc/middle/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
t
}

ty::ty_open(..) => {
self.tcx().sess.bug("Cannot freshen an open existential type");
}

ty::ty_open(..) |
ty::ty_bool |
ty::ty_char |
ty::ty_int(..) |
Expand Down
17 changes: 16 additions & 1 deletion src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1457,11 +1457,26 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(AmbiguousBuiltin)
}

ty::ty_open(ty) => {
// these only crop up in trans, and represent an
// "opened" unsized/existential type (one that has
// been dereferenced)
match bound {
ty::BoundCopy |
ty::BoundSync |
ty::BoundSend => {
Ok(If(vec!(ty)))
}

ty::BoundSized => {
Err(Unimplemented)
}
}
}
ty::ty_err => {
Ok(If(Vec::new()))
}

ty::ty_open(_) |
ty::ty_infer(ty::FreshTy(_)) |
ty::ty_infer(ty::FreshIntTy(_)) => {
self.tcx().sess.bug(
Expand Down
16 changes: 15 additions & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub struct CrateAnalysis<'tcx> {
pub glob_map: Option<GlobMap>,
}

#[derive(Copy, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct field<'tcx> {
pub name: ast::Name,
pub mt: mt<'tcx>
Expand Down Expand Up @@ -7212,6 +7212,12 @@ impl<'tcx> HasProjectionTypes for FnSig<'tcx> {
}
}

impl<'tcx> HasProjectionTypes for field<'tcx> {
fn has_projection_types(&self) -> bool {
self.mt.ty.has_projection_types()
}
}

impl<'tcx> HasProjectionTypes for BareFnTy<'tcx> {
fn has_projection_types(&self) -> bool {
self.sig.has_projection_types()
Expand Down Expand Up @@ -7311,3 +7317,11 @@ impl<'tcx> Repr<'tcx> for UnboxedClosureUpvar<'tcx> {
self.ty.repr(tcx))
}
}

impl<'tcx> Repr<'tcx> for field<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("field({},{})",
self.name.repr(tcx),
self.mt.repr(tcx))
}
}
9 changes: 9 additions & 0 deletions src/librustc/middle/ty_fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> {
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::field<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::field<'tcx> {
ty::field {
name: self.name,
mt: self.mt.fold_with(folder),
}
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::Region {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Region {
folder.fold_region(*self)
Expand Down
17 changes: 9 additions & 8 deletions src/librustc_trans/trans/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,21 @@ use std::rc::Rc;
use llvm::{ValueRef, True, IntEQ, IntNE};
use back::abi::FAT_PTR_ADDR;
use middle::subst;
use middle::subst::Subst;
use middle::ty::{mod, Ty, UnboxedClosureTyper};
use middle::ty::Disr;
use syntax::ast;
use syntax::attr;
use syntax::attr::IntType;
use trans::_match;
use trans::build::*;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::common::*;
use trans::datum;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
use middle::ty::{self, Ty, UnboxedClosureTyper};
use middle::ty::Disr;
use syntax::ast;
use syntax::attr;
use syntax::attr::IntType;
use util::ppaux::ty_to_string;

type Hint = attr::ReprAttr;
Expand Down Expand Up @@ -159,7 +159,8 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
ty::ty_struct(def_id, substs) => {
let fields = ty::lookup_struct_fields(cx.tcx(), def_id);
let mut ftys = fields.iter().map(|field| {
ty::lookup_field_type(cx.tcx(), def_id, field.id, substs)
let fty = ty::lookup_field_type(cx.tcx(), def_id, field.id, substs);
monomorphize::normalize_associated_type(cx.tcx(), &fty)
}).collect::<Vec<_>>();
let packed = ty::lookup_packed(cx.tcx(), def_id);
let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag();
Expand Down Expand Up @@ -432,7 +433,7 @@ fn get_cases<'tcx>(tcx: &ty::ctxt<'tcx>,
-> Vec<Case<'tcx>> {
ty::enum_variants(tcx, def_id).iter().map(|vi| {
let arg_tys = vi.args.iter().map(|&raw_ty| {
raw_ty.subst(tcx, substs)
monomorphize::apply_param_substs(tcx, substs, &raw_ty)
}).collect();
Case { discr: vi.disr_val, tys: arg_tys }
}).collect()
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use std::vec::Vec;
use syntax::ast::Ident;
use syntax::ast;
use syntax::ast_map::{PathElem, PathName};
use syntax::codemap::Span;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use syntax::parse::token;
use util::common::memoized;
Expand Down Expand Up @@ -114,8 +114,9 @@ pub fn normalize_ty<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
}

// Is the type's representation size known at compile time?
pub fn type_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
ty::type_contents(cx, ty).is_sized(cx)
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
let param_env = ty::empty_parameter_environment(tcx);
ty::type_is_sized(&param_env, DUMMY_SP, ty)
}

pub fn lltype_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
Expand Down
12 changes: 7 additions & 5 deletions src/librustc_trans/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ use trans::debuginfo;
use trans::glue;
use trans::machine;
use trans::meth;
use trans::monomorphize;
use trans::inline;
use trans::tvec;
use trans::type_of;
Expand Down Expand Up @@ -1318,7 +1319,9 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
{
match ty.sty {
ty::ty_struct(did, substs) => {
op(0, struct_fields(tcx, did, substs).index(&FullRange))
let fields = struct_fields(tcx, did, substs);
let fields = monomorphize::normalize_associated_type(tcx, &fields);
op(0, fields.index(&FullRange))
}

ty::ty_tup(ref v) => {
Expand All @@ -1340,10 +1343,9 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
def::DefVariant(enum_id, variant_id, _) => {
let variant_info = ty::enum_variant_with_id(
tcx, enum_id, variant_id);
op(variant_info.disr_val,
struct_fields(tcx,
variant_id,
substs).index(&FullRange))
let fields = struct_fields(tcx, variant_id, substs);
let fields = monomorphize::normalize_associated_type(tcx, &fields);
op(variant_info.disr_val, fields.index(&FullRange))
}
_ => {
tcx.sess.bug("resolve didn't map this expr to a \
Expand Down
2 changes: 0 additions & 2 deletions src/librustc_trans/trans/monomorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,6 @@ pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
-> T
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
{
assert!(param_substs.regions.is_erased());

let substituted = value.subst(tcx, param_substs);
normalize_associated_type(tcx, &substituted)
}
Expand Down
47 changes: 1 addition & 46 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ use middle::const_eval;
use middle::def;
use middle::resolve_lifetime as rl;
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::subst::{VecPerParamSpace};
use middle::traits;
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
Expand Down Expand Up @@ -244,7 +243,7 @@ pub fn opt_ast_region_to_region<'tcx>(

/// Given a path `path` that refers to an item `I` with the declared generics `decl_generics`,
/// returns an appropriate set of substitutions for this particular reference to `I`.
fn ast_path_substs_for_ty<'tcx>(
pub fn ast_path_substs_for_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
decl_generics: &ty::Generics<'tcx>,
Expand Down Expand Up @@ -762,50 +761,6 @@ pub fn ast_path_to_ty<'tcx>(
TypeAndSubsts { substs: substs, ty: ty }
}

/// Returns the type that this AST path refers to. If the path has no type
/// parameters and the corresponding type has type parameters, fresh type
/// and/or region variables are substituted.
///
/// This is used when checking the constructor in struct literals.
pub fn ast_path_to_ty_relaxed<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts<'tcx>
{
let tcx = this.tcx();
let ty::TypeScheme {
generics,
ty: decl_ty
} = this.get_item_type_scheme(did);

let wants_params =
generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);

let needs_defaults =
wants_params &&
path.segments.iter().all(|s| s.parameters.is_empty());

let substs = if needs_defaults {
let type_params: Vec<_> = range(0, generics.types.len(TypeSpace))
.map(|_| this.ty_infer(path.span)).collect();
let region_params =
rscope.anon_regions(path.span, generics.regions.len(TypeSpace))
.unwrap();
Substs::new(VecPerParamSpace::params_from_type(type_params),
VecPerParamSpace::params_from_type(region_params))
} else {
ast_path_substs_for_ty(this, rscope, &generics, path)
};

let ty = decl_ty.subst(tcx, &substs);
TypeAndSubsts {
substs: substs,
ty: ty,
}
}

/// Converts the given AST type to a built-in type. A "built-in type" is, at
/// present, either a core numeric type, a string, or `Box`.
pub fn ast_ty_to_builtin_ty<'tcx>(
Expand Down
53 changes: 44 additions & 9 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ use middle::mem_categorization as mc;
use middle::mem_categorization::McResult;
use middle::pat_util::{self, pat_id_map};
use middle::region::CodeExtent;
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
use middle::traits;
use middle::ty::{FnSig, VariantInfo, TypeScheme};
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
Expand Down Expand Up @@ -1947,6 +1947,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

/// Returns the type that this AST path refers to. If the path has no type
/// parameters and the corresponding type has type parameters, fresh type
/// and/or region variables are substituted.
///
/// This is used when checking the constructor in struct literals.
fn instantiate_struct_literal_ty(&self,
did: ast::DefId,
path: &ast::Path)
-> TypeAndSubsts<'tcx>
{
let tcx = self.tcx();

let ty::TypeScheme { generics, ty: decl_ty } = ty::lookup_item_type(tcx, did);

let wants_params =
generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);

let needs_defaults =
wants_params &&
path.segments.iter().all(|s| s.parameters.is_empty());

let substs = if needs_defaults {
let tps =
self.infcx().next_ty_vars(generics.types.len(TypeSpace));
let rps =
self.infcx().region_vars_for_defs(path.span,
generics.regions.get_slice(TypeSpace));
Substs::new_type(tps, rps)
} else {
astconv::ast_path_substs_for_ty(self, self, &generics, path)
};

let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);

TypeAndSubsts { substs: substs, ty: ty }
}

pub fn write_nil(&self, node_id: ast::NodeId) {
self.write_ty(node_id, ty::mk_nil(self.tcx()));
}
Expand Down Expand Up @@ -3490,17 +3527,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
expected_field_type =
ty::lookup_field_type(
tcx, class_id, field_id, substitutions);
expected_field_type =
fcx.normalize_associated_types_in(
field.span, &expected_field_type);
class_field_map.insert(
field.ident.node.name, (field_id, true));
fields_found += 1;
}
}

// Make sure to give a type to the field even if there's
// an error, so we can continue typechecking
check_expr_coercable_to_type(
fcx,
&*field.expr,
expected_field_type);
check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type);
}

if error_happened {
Expand Down Expand Up @@ -4149,10 +4187,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
// parameters correctly.
let actual_structure_type = fcx.expr_ty(&*expr);
if !ty::type_is_error(actual_structure_type) {
let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx,
fcx,
struct_id,
path);
let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path);
match fcx.mk_subty(false,
infer::Misc(path.span),
actual_structure_type,
Expand Down
7 changes: 7 additions & 0 deletions src/test/compile-fail/recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//~^^^^^^^^^^ ERROR overflow
//
// We also get a second error message at the top of file (dummy
// span). This is not helpful, but also kind of annoying to prevent,
// so for now just live with it, since we also get a second message
// that is more helpful.

enum Nil {NilValue}
struct Cons<T> {head:int, tail:T}
trait Dot {fn dot(&self, other:Self) -> int;}
Expand Down
Loading