about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-01-07 17:35:00 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-01-07 17:35:00 -0800
commitbcebec508422e3dc88215a621f3b51beb88b0330 (patch)
treeef21ffee1018a7073fc57aa9eeb4130abec97656
parent51357e04be5482d746053646b2af68cd34563ced (diff)
parentcb98c3d93a4c0e79ae87a04a6d3a439ac8ed87b1 (diff)
downloadrust-bcebec508422e3dc88215a621f3b51beb88b0330.tar.gz
rust-bcebec508422e3dc88215a621f3b51beb88b0330.zip
rollup merge of #20706: nikomatsakis/assoc-types-projections-in-structs-issue-20470
Conflicts:
	src/librustc_trans/trans/expr.rs
-rw-r--r--src/librustc/middle/infer/freshen.rs5
-rw-r--r--src/librustc/middle/traits/select.rs17
-rw-r--r--src/librustc/middle/ty.rs16
-rw-r--r--src/librustc/middle/ty_fold.rs9
-rw-r--r--src/librustc_trans/trans/adt.rs17
-rw-r--r--src/librustc_trans/trans/common.rs7
-rw-r--r--src/librustc_trans/trans/expr.rs12
-rw-r--r--src/librustc_trans/trans/monomorphize.rs2
-rw-r--r--src/librustc_typeck/astconv.rs47
-rw-r--r--src/librustc_typeck/check/mod.rs53
-rw-r--r--src/test/compile-fail/recursion.rs7
-rw-r--r--src/test/run-pass/associated-types-ref-from-struct.rs62
-rw-r--r--src/test/run-pass/associated-types-ref-in-struct-literal.rs29
13 files changed, 204 insertions, 79 deletions
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<GlobMap>,
 }
 
-#[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<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)
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::<Vec<_>>();
             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<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()
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(&param_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<T> {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 <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.
+
+// Test associated type references in structure fields.
+
+trait Test {
+    type V;
+
+    fn test(&self, value: &Self::V) -> bool;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+struct TesterPair<T:Test> {
+    tester: T,
+    value: T::V,
+}
+
+impl<T:Test> TesterPair<T> {
+    fn new(tester: T, value: T::V) -> TesterPair<T> {
+        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 <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.
+
+// Test associated type references in a struct literal. Issue #20535.
+
+pub trait Foo {
+    type Bar;
+}
+
+impl Foo for int {
+    type Bar = int;
+}
+
+struct Thing<F: Foo> {
+    a: F,
+    b: F::Bar,
+}
+
+fn main() {
+    let thing = Thing{a: 1i, b: 2i};
+    assert_eq!(thing.a + 1, thing.b);
+}