diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index 02c52f82967..6bc424fdf95 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -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(..) | diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index c5ed9adb1bc..f42f43d2576 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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( diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cc119e2fb4c..33efc1fa10b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -107,7 +107,7 @@ pub struct CrateAnalysis<'tcx> { pub glob_map: Option, } -#[derive(Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct field<'tcx> { pub name: ast::Name, pub mt: mt<'tcx> @@ -7240,6 +7240,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() @@ -7339,3 +7345,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)) + } +} diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 424e357d8d4..dedd69deabb 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -273,6 +273,15 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitRef<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::field<'tcx> { + fn fold_with>(&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>(&self, folder: &mut F) -> ty::Region { folder.fold_region(*self) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 59b4643fdc5..0275942e1d5 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -51,7 +51,11 @@ 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; @@ -59,13 +63,9 @@ 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; @@ -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::>(); let packed = ty::lookup_packed(cx.tcx(), def_id); let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); @@ -432,7 +433,7 @@ fn get_cases<'tcx>(tcx: &ty::ctxt<'tcx>, -> Vec> { 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() diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 9b65259ad51..1a74137c10d 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -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; @@ -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(¶m_env, DUMMY_SP, ty) } pub fn lltype_is_sized<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 2d1a151c2b8..0e7dd42d320 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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; @@ -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)[]) + let fields = struct_fields(tcx, did, substs); + let fields = monomorphize::normalize_associated_type(tcx, &fields); + op(0, &fields[]) } ty::ty_tup(ref v) => { @@ -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)[]) + let fields = struct_fields(tcx, variant_id, substs); + let fields = monomorphize::normalize_associated_type(tcx, &fields); + op(variant_info.disr_val, &fields.index[]) } _ => { tcx.sess.bug("resolve didn't map this expr to a \ diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 6d2288e913f..435f94f35fa 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -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) } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 867d6f322d1..2046ee015f6 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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, @@ -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>, @@ -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>( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2b7f615dc12..b98b327100c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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}; @@ -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())); } @@ -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 { @@ -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, diff --git a/src/test/compile-fail/recursion.rs b/src/test/compile-fail/recursion.rs index 67177eff9f9..da05514f763 100644 --- a/src/test/compile-fail/recursion.rs +++ b/src/test/compile-fail/recursion.rs @@ -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 {head:int, tail:T} trait Dot {fn dot(&self, other:Self) -> int;} diff --git a/src/test/run-pass/associated-types-ref-from-struct.rs b/src/test/run-pass/associated-types-ref-from-struct.rs new file mode 100644 index 00000000000..3c7cc7c4975 --- /dev/null +++ b/src/test/run-pass/associated-types-ref-from-struct.rs @@ -0,0 +1,62 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test associated type references in structure fields. + +trait Test { + type V; + + fn test(&self, value: &Self::V) -> bool; +} + +/////////////////////////////////////////////////////////////////////////// + +struct TesterPair { + tester: T, + value: T::V, +} + +impl TesterPair { + fn new(tester: T, value: T::V) -> TesterPair { + TesterPair { tester: tester, value: value } + } + + fn test(&self) -> bool { + self.tester.test(&self.value) + } +} + +/////////////////////////////////////////////////////////////////////////// + +struct EqU32(u32); +impl Test for EqU32 { + type V = u32; + + fn test(&self, value: &u32) -> bool { + self.0 == *value + } +} + +struct EqI32(i32); +impl Test for EqI32 { + type V = i32; + + fn test(&self, value: &i32) -> bool { + self.0 == *value + } +} + +fn main() { + let tester = TesterPair::new(EqU32(22), 23); + tester.test(); + + let tester = TesterPair::new(EqI32(22), 23); + tester.test(); +} diff --git a/src/test/run-pass/associated-types-ref-in-struct-literal.rs b/src/test/run-pass/associated-types-ref-in-struct-literal.rs new file mode 100644 index 00000000000..b51d44a0c24 --- /dev/null +++ b/src/test/run-pass/associated-types-ref-in-struct-literal.rs @@ -0,0 +1,29 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test associated type references in a struct literal. Issue #20535. + +pub trait Foo { + type Bar; +} + +impl Foo for int { + type Bar = int; +} + +struct Thing { + a: F, + b: F::Bar, +} + +fn main() { + let thing = Thing{a: 1i, b: 2i}; + assert_eq!(thing.a + 1, thing.b); +}