Skip to content

Commit 250dc4e

Browse files
committed
Allow anonymized return types to be declared in associated types.
1 parent 608ab6b commit 250dc4e

File tree

8 files changed

+1089
-27
lines changed

8 files changed

+1089
-27
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1598,7 +1598,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
15981598
(None, _) => {
15991599
span_err!(this.tcx().sess, ast_ty.span, E0439,
16001600
"anonymized types are not allowed outside of function and \
1601-
impl method return types");
1601+
impl method return types and impl associated types");
16021602
this.tcx().types.err
16031603
}
16041604
(Some(_), Err(_)) => this.tcx().types.err,

src/librustc_typeck/check/closure.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
8484
expr.id,
8585
&fn_sig,
8686
decl,
87+
None,
8788
expr.id,
8889
&*body,
8990
fcx.inh);

src/librustc_typeck/check/mod.rs

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,13 @@ pub struct Inherited<'a, 'tcx: 'a> {
172172

173173
deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
174174

175-
// Anonymized types found in explicit return types and their
176-
// associated fresh inference variable. Writeback resolves these
177-
// variables to get the concrete type, which can be used to
178-
// deanonymize TyAnon, after typeck is done with all functions.
179-
anon_types: RefCell<Vec<(DefId, Ty<'tcx>)>>,
175+
// Anonymized types found in explicit return types, their param
176+
// space of definition (TypeSpace in associated types, FnSpace in
177+
// function return types) and their respective fresh inference
178+
// variable. Writeback resolves these variables to get the concrete
179+
// type, which can be used to deanonymize TyAnon, after typeck is
180+
// done processing all functions.
181+
anon_types: RefCell<Vec<(DefId, ParamSpace, Ty<'tcx>)>>,
180182
}
181183

182184
trait DeferredCallResolution<'tcx> {
@@ -364,6 +366,7 @@ fn static_inherited_fields<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
364366

365367
struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
366368
struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
369+
struct CheckAnonTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
367370

368371
impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
369372
fn visit_item(&mut self, i: &'tcx ast::Item) {
@@ -390,6 +393,22 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
390393
}
391394
}
392395

396+
impl<'a, 'tcx> Visitor<'tcx> for CheckAnonTypesVisitor<'a, 'tcx> {
397+
fn visit_ty(&mut self, ty: &'tcx ast::Ty) {
398+
if let ast::TyAnon(_) = ty.node {
399+
if !self.ccx.tcx.tcache.borrow().contains_key(&local_def(ty.id)) {
400+
span_err!(self.ccx.tcx.sess, ty.span, E0442,
401+
"anonymized types must be used in a return \
402+
type in the same impl");
403+
}
404+
}
405+
visit::walk_ty(self, ty);
406+
}
407+
408+
// Do not recurse into items.
409+
fn visit_item(&mut self, _: &ast::Item) {}
410+
}
411+
393412
pub fn check_item_types(ccx: &CrateCtxt) {
394413
let krate = ccx.tcx.map.krate();
395414
let mut visit = wf::CheckTypeWellFormedVisitor::new(ccx);
@@ -425,6 +444,7 @@ pub fn check_item_types(ccx: &CrateCtxt) {
425444
}
426445

427446
fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
447+
impl_id: Option<ast::NodeId>,
428448
decl: &'tcx ast::FnDecl,
429449
body: &'tcx ast::Block,
430450
fn_id: ast::NodeId,
@@ -449,7 +469,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
449469
&fn_sig);
450470

451471
let fcx = check_fn(ccx, fn_ty.unsafety, fn_id, &fn_sig,
452-
decl, fn_id, body, &inh);
472+
decl, impl_id, fn_id, body, &inh);
453473

454474
fcx.select_all_obligations_and_apply_defaults();
455475
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
@@ -559,6 +579,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
559579
unsafety_id: ast::NodeId,
560580
fn_sig: &ty::FnSig<'tcx>,
561581
decl: &'tcx ast::FnDecl,
582+
impl_id: Option<ast::NodeId>,
562583
fn_id: ast::NodeId,
563584
body: &'tcx ast::Block,
564585
inherited: &'a Inherited<'a, 'tcx>)
@@ -632,7 +653,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
632653

633654
check_block_with_expected(&fcx, body, match ret_ty {
634655
ty::FnConverging(result_type) => {
635-
ExpectHasType(fcx.instantiate_anon_types(result_type))
656+
ExpectHasType(fcx.instantiate_anon_types(result_type, fn_id, impl_id))
636657
}
637658
ty::FnDiverging => NoExpectation
638659
});
@@ -725,7 +746,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
725746
ast::ItemFn(ref decl, _, _, _, _, ref body) => {
726747
let fn_pty = ccx.tcx.lookup_item_type(ast_util::local_def(it.id));
727748
let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
728-
check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env);
749+
check_bare_fn(ccx, None, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env);
729750
}
730751
ast::ItemImpl(_, _, _, _, _, ref impl_items) => {
731752
debug!("ItemImpl {} with id {}", it.ident, it.id);
@@ -738,15 +759,23 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
738759
check_const(ccx, impl_item.span, &*expr, impl_item.id)
739760
}
740761
ast::MethodImplItem(ref sig, ref body) => {
741-
check_method_body(ccx, &impl_pty.generics, sig, body,
742-
impl_item.id, impl_item.span);
762+
check_method_body(ccx, Some(it.id), &impl_pty.generics, sig,
763+
body, impl_item.id, impl_item.span);
743764
}
744765
ast::TypeImplItem(_) |
745766
ast::MacImplItem(_) => {
746767
// Nothing to do here.
747768
}
748769
}
749770
}
771+
772+
// Check that if we had anonymized types in an associated type,
773+
// they were assigned by one of the methods in this impl.
774+
for impl_item in impl_items {
775+
if let ast::TypeImplItem(ref ty) = impl_item.node {
776+
CheckAnonTypesVisitor { ccx: ccx }.visit_ty(ty);
777+
}
778+
}
750779
}
751780
ast::ItemTrait(_, _, _, ref trait_items) => {
752781
let trait_def = ccx.tcx.lookup_trait_def(local_def(it.id));
@@ -758,8 +787,8 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
758787
ast::MethodTraitItem(ref sig, Some(ref body)) => {
759788
check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
760789

761-
check_method_body(ccx, &trait_def.generics, sig, body,
762-
trait_item.id, trait_item.span);
790+
check_method_body(ccx, None, &trait_def.generics, sig,
791+
body, trait_item.id, trait_item.span);
763792
}
764793
ast::MethodTraitItem(ref sig, None) => {
765794
check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
@@ -842,6 +871,7 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
842871
/// * `self_bound`: bound for the `Self` type parameter, if any
843872
/// * `method`: the method definition
844873
fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
874+
impl_id: Option<ast::NodeId>,
845875
item_generics: &ty::Generics<'tcx>,
846876
sig: &'tcx ast::MethodSig,
847877
body: &'tcx ast::Block,
@@ -853,7 +883,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
853883
let fty = ccx.tcx.node_id_to_type(id);
854884
debug!("check_method_body: fty={:?}", fty);
855885

856-
check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
886+
check_bare_fn(ccx, impl_id, &sig.decl, body, id, span, fty, param_env);
857887
}
858888

859889
fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
@@ -1363,15 +1393,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13631393

13641394
/// Replace all anonymized types with fresh inference variables
13651395
/// and record them for writeback.
1366-
fn instantiate_anon_types(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
1396+
fn instantiate_anon_types(&self, ty: Ty<'tcx>, fn_id: ast::NodeId,
1397+
impl_id: Option<ast::NodeId>) -> Ty<'tcx> {
13671398
let tcx = self.tcx();
13681399
let mut anon_types = self.inh.anon_types.borrow_mut();
13691400
ty.fold_with(&mut BottomUpFolder {
13701401
tcx: tcx,
13711402
fldop: |ty| {
13721403
if let ty::TyAnon(def_id, _, ref data) = ty.sty {
1404+
// Do not instantiate an `impl Trait` type unless it was
1405+
// defined in the same function's return type or in an
1406+
// associated type of the impl, in the case of methods.
1407+
if def_id.krate != ast::LOCAL_CRATE {
1408+
return ty;
1409+
}
1410+
1411+
let parent = tcx.map.get_parent(def_id.node);
1412+
let param_space = if parent == fn_id {
1413+
subst::FnSpace
1414+
} else if Some(tcx.map.get_parent(parent)) == impl_id {
1415+
subst::TypeSpace
1416+
} else {
1417+
return ty;
1418+
};
1419+
13731420
let ty_var = self.infcx().next_ty_var();
1374-
anon_types.push((def_id, ty_var));
1421+
anon_types.push((def_id, param_space, ty_var));
13751422

13761423
let span = tcx.map.def_id_span(def_id, codemap::DUMMY_SP);
13771424
let cause = traits::ObligationCause::new(span, self.body_id,

src/librustc_typeck/check/writeback.rs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
use self::ResolveReason::*;
1515

1616
use astconv::AstConv;
17-
use check::FnCtxt;
17+
use check::{FnCtxt, demand};
1818
use middle::pat_util;
19+
use middle::subst::{FnSpace, TypeSpace};
1920
use middle::ty::{self, Ty, MethodCall, MethodCallee};
2021
use middle::ty_fold::{TypeFolder,TypeFoldable};
2122
use middle::infer;
@@ -246,12 +247,35 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
246247
return
247248
}
248249

249-
for &(def_id, concrete_ty) in &*self.fcx.inh.anon_types.borrow() {
250-
let concrete_ty = self.resolve(&concrete_ty, ResolvingAnonTy(def_id));
251-
self.fcx.tcx().tcache.borrow_mut().insert(def_id, ty::TypeScheme {
252-
ty: concrete_ty,
253-
generics: ty::Generics::empty()
254-
});
250+
for &(def_id, param_space, concrete_ty) in &*self.fcx.inh.anon_types.borrow() {
251+
let reason = ResolvingAnonTy(def_id);
252+
let concrete_ty = self.resolve(&concrete_ty, reason);
253+
let old_ty = self.fcx.tcx().tcache.borrow_mut().get(&def_id).as_ref().map(|t| t.ty);
254+
255+
if let Some(old_ty) = old_ty {
256+
// Ensure all anonymized type assignments agree with eachother.
257+
demand::eqtype(self.fcx, reason.span(self.fcx.tcx()), old_ty, concrete_ty);
258+
} else {
259+
// Do not let method type parameters escape into anonymized types
260+
// defined inside an associated type, which is only parametrized
261+
// on the impl type parameters.
262+
if param_space == TypeSpace {
263+
for ty in concrete_ty.walk() {
264+
if let ty::TyParam(ty::ParamTy { space: FnSpace, .. }) = ty.sty {
265+
let span = reason.span(self.fcx.tcx());
266+
span_err!(self.fcx.tcx().sess, span, E0441,
267+
"method type parameter `{}` cannot be used in an \
268+
anonymized type defined in an associated type",
269+
ty);
270+
}
271+
}
272+
}
273+
274+
self.fcx.tcx().tcache.borrow_mut().insert(def_id, ty::TypeScheme {
275+
ty: concrete_ty,
276+
generics: ty::Generics::empty()
277+
});
278+
}
255279
}
256280
}
257281

@@ -441,7 +465,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
441465

442466
ResolvingAnonTy(_) => {
443467
let span = self.reason.span(self.tcx);
444-
span_err!(self.tcx.sess, span, E0399,
468+
span_err!(self.tcx.sess, span, E0440,
445469
"cannot determine a concrete type for this anonymized type")
446470
}
447471
}

src/librustc_typeck/collect.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,9 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
916916
"associated types are not allowed in inherent impls");
917917
}
918918

919-
let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
919+
let anon_scope = Some(AnonTypeScope::new(&ty_generics));
920+
let rscope = MaybeWithAnonTypes::new(ExplicitRscope, anon_scope);
921+
let typ = ccx.icx(&ty_predicates).to_ty(&rscope, ty);
920922

921923
convert_associated_type(ccx, ImplContainer(local_def(it.id)),
922924
impl_item.ident, impl_item.id, impl_item.vis,

src/librustc_typeck/diagnostics.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2474,6 +2474,9 @@ register_diagnostics! {
24742474
// type `{}` was overridden
24752475
E0436, // functional record update requires a struct
24762476
E0439, // anonymized types are not allowed outside of function and
2477-
// impl method return types
2478-
E0440 // cannot determine a concrete type for this anonymized type
2477+
// impl method return types and impl associated types
2478+
E0440, // cannot determine a concrete type for this anonymized type
2479+
E0441, // method type parameter `{}` cannot be used in an anonymized type
2480+
// defined in an associated type
2481+
E0442 // anonymized types must be used in a return type in the same impl
24792482
}

0 commit comments

Comments
 (0)