about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-01-07 18:45:36 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-01-07 20:26:21 -0500
commitcb98c3d93a4c0e79ae87a04a6d3a439ac8ed87b1 (patch)
tree0cd67e45ea49a554680a30488aae4b7f2b184369
parent18f426e647d05a422d0fcae65c8a87a8e4befb69 (diff)
downloadrust-cb98c3d93a4c0e79ae87a04a6d3a439ac8ed87b1.tar.gz
rust-cb98c3d93a4c0e79ae87a04a6d3a439ac8ed87b1.zip
Normalize types of fields in struct literals during type-checking.
Fixes #20535.
-rw-r--r--src/librustc_typeck/astconv.rs47
-rw-r--r--src/librustc_typeck/check/mod.rs53
-rw-r--r--src/test/run-pass/associated-types-ref-in-struct-literal.rs29
3 files changed, 74 insertions, 55 deletions
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 265ebe00d53..3534d3ff3af 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 9563dd45ca2..87175279bae 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/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);
+}