Skip to content

Commit cb98c3d

Browse files
committed
Normalize types of fields in struct literals during type-checking.
Fixes #20535.
1 parent 18f426e commit cb98c3d

File tree

3 files changed

+74
-55
lines changed

3 files changed

+74
-55
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ use middle::const_eval;
5252
use middle::def;
5353
use middle::resolve_lifetime as rl;
5454
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
55-
use middle::subst::{VecPerParamSpace};
5655
use middle::traits;
5756
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
5857
use rscope::{self, UnelidableRscope, RegionScope, SpecificRscope,
@@ -244,7 +243,7 @@ pub fn opt_ast_region_to_region<'tcx>(
244243

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

765-
/// Returns the type that this AST path refers to. If the path has no type
766-
/// parameters and the corresponding type has type parameters, fresh type
767-
/// and/or region variables are substituted.
768-
///
769-
/// This is used when checking the constructor in struct literals.
770-
pub fn ast_path_to_ty_relaxed<'tcx>(
771-
this: &AstConv<'tcx>,
772-
rscope: &RegionScope,
773-
did: ast::DefId,
774-
path: &ast::Path)
775-
-> TypeAndSubsts<'tcx>
776-
{
777-
let tcx = this.tcx();
778-
let ty::TypeScheme {
779-
generics,
780-
ty: decl_ty
781-
} = this.get_item_type_scheme(did);
782-
783-
let wants_params =
784-
generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
785-
786-
let needs_defaults =
787-
wants_params &&
788-
path.segments.iter().all(|s| s.parameters.is_empty());
789-
790-
let substs = if needs_defaults {
791-
let type_params: Vec<_> = range(0, generics.types.len(TypeSpace))
792-
.map(|_| this.ty_infer(path.span)).collect();
793-
let region_params =
794-
rscope.anon_regions(path.span, generics.regions.len(TypeSpace))
795-
.unwrap();
796-
Substs::new(VecPerParamSpace::params_from_type(type_params),
797-
VecPerParamSpace::params_from_type(region_params))
798-
} else {
799-
ast_path_substs_for_ty(this, rscope, &generics, path)
800-
};
801-
802-
let ty = decl_ty.subst(tcx, &substs);
803-
TypeAndSubsts {
804-
substs: substs,
805-
ty: ty,
806-
}
807-
}
808-
809764
/// Converts the given AST type to a built-in type. A "built-in type" is, at
810765
/// present, either a core numeric type, a string, or `Box`.
811766
pub fn ast_ty_to_builtin_ty<'tcx>(

src/librustc_typeck/check/mod.rs

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ use middle::mem_categorization as mc;
9090
use middle::mem_categorization::McResult;
9191
use middle::pat_util::{self, pat_id_map};
9292
use middle::region::CodeExtent;
93-
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace};
93+
use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
9494
use middle::traits;
9595
use middle::ty::{FnSig, VariantInfo, TypeScheme};
9696
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
@@ -1947,6 +1947,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19471947
}
19481948
}
19491949

1950+
/// Returns the type that this AST path refers to. If the path has no type
1951+
/// parameters and the corresponding type has type parameters, fresh type
1952+
/// and/or region variables are substituted.
1953+
///
1954+
/// This is used when checking the constructor in struct literals.
1955+
fn instantiate_struct_literal_ty(&self,
1956+
did: ast::DefId,
1957+
path: &ast::Path)
1958+
-> TypeAndSubsts<'tcx>
1959+
{
1960+
let tcx = self.tcx();
1961+
1962+
let ty::TypeScheme { generics, ty: decl_ty } = ty::lookup_item_type(tcx, did);
1963+
1964+
let wants_params =
1965+
generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
1966+
1967+
let needs_defaults =
1968+
wants_params &&
1969+
path.segments.iter().all(|s| s.parameters.is_empty());
1970+
1971+
let substs = if needs_defaults {
1972+
let tps =
1973+
self.infcx().next_ty_vars(generics.types.len(TypeSpace));
1974+
let rps =
1975+
self.infcx().region_vars_for_defs(path.span,
1976+
generics.regions.get_slice(TypeSpace));
1977+
Substs::new_type(tps, rps)
1978+
} else {
1979+
astconv::ast_path_substs_for_ty(self, self, &generics, path)
1980+
};
1981+
1982+
let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
1983+
1984+
TypeAndSubsts { substs: substs, ty: ty }
1985+
}
1986+
19501987
pub fn write_nil(&self, node_id: ast::NodeId) {
19511988
self.write_ty(node_id, ty::mk_nil(self.tcx()));
19521989
}
@@ -3490,17 +3527,18 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
34903527
expected_field_type =
34913528
ty::lookup_field_type(
34923529
tcx, class_id, field_id, substitutions);
3530+
expected_field_type =
3531+
fcx.normalize_associated_types_in(
3532+
field.span, &expected_field_type);
34933533
class_field_map.insert(
34943534
field.ident.node.name, (field_id, true));
34953535
fields_found += 1;
34963536
}
34973537
}
3538+
34983539
// Make sure to give a type to the field even if there's
34993540
// an error, so we can continue typechecking
3500-
check_expr_coercable_to_type(
3501-
fcx,
3502-
&*field.expr,
3503-
expected_field_type);
3541+
check_expr_coercable_to_type(fcx, &*field.expr, expected_field_type);
35043542
}
35053543

35063544
if error_happened {
@@ -4149,10 +4187,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
41494187
// parameters correctly.
41504188
let actual_structure_type = fcx.expr_ty(&*expr);
41514189
if !ty::type_is_error(actual_structure_type) {
4152-
let type_and_substs = astconv::ast_path_to_ty_relaxed(fcx,
4153-
fcx,
4154-
struct_id,
4155-
path);
4190+
let type_and_substs = fcx.instantiate_struct_literal_ty(struct_id, path);
41564191
match fcx.mk_subty(false,
41574192
infer::Misc(path.span),
41584193
actual_structure_type,
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test associated type references in a struct literal. Issue #20535.
12+
13+
pub trait Foo {
14+
type Bar;
15+
}
16+
17+
impl Foo for int {
18+
type Bar = int;
19+
}
20+
21+
struct Thing<F: Foo> {
22+
a: F,
23+
b: F::Bar,
24+
}
25+
26+
fn main() {
27+
let thing = Thing{a: 1i, b: 2i};
28+
assert_eq!(thing.a + 1, thing.b);
29+
}

0 commit comments

Comments
 (0)