Skip to content

Commit df8debf

Browse files
committed
Auto merge of #38920 - petrochenkov:selfimpl, r=eddyb
Partially implement RFC 1647 (`Self` in impl headers) The name resolution part is easy, but the typeck part contains an unexpected problem. It turns out that `Self` type *depends* on bounds and `where` clauses, so we need to convert them first to determine what the `Self` type is! If bounds/`where` clauses can refer to `Self` then we have a cyclic dependency. This is required to support impls like this: ``` // Found in libcollections impl<I: IntoIterator> SpecExtend<I> for LinkedList<I::Item> { .... } ^^^^^ associated type `Item` is found using information from bounds ``` I'm not yet sure how to resolve this issue. One possible solution (that feels hacky) is to make two passes over generics - first collect predicates ignoring everything involving `Self`, then determine `Self`, then collect predicates again without ignoring anything. (Some kind of lazy on-demand checking or something looks like a proper solution.) This patch in its current state doesn't solve the problem with `Self` in bounds, so the only observable things it does is improving error messages and supporting `impl Trait<Self> for Type {}`. There's also a question about feature gating. It's non-trivial to *detect* "newly resolved" `Self`s to feature gate them, but it's simple to *enable* the new resolution behavior when the feature gate is already specified. Alternatively this can be considered a bug fix and merged without a feature gate. cc #38864 r? @nikomatsakis cc @eddyb Whitespace ignoring diff https://github.com/rust-lang/rust/pull/38920/files?w=1
2 parents 94d4589 + f9bdf34 commit df8debf

File tree

5 files changed

+122
-67
lines changed

5 files changed

+122
-67
lines changed

Diff for: src/librustc_resolve/lib.rs

+61-53
Original file line numberDiff line numberDiff line change
@@ -1548,7 +1548,10 @@ impl<'a> Resolver<'a> {
15481548
}
15491549

15501550
ItemKind::DefaultImpl(_, ref trait_ref) => {
1551-
self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
1551+
self.with_optional_trait_ref(Some(trait_ref), |this, _| {
1552+
// Resolve type arguments in trait path
1553+
visit::walk_trait_ref(this, trait_ref);
1554+
});
15521555
}
15531556
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
15541557
self.resolve_implementation(generics,
@@ -1712,7 +1715,6 @@ impl<'a> Resolver<'a> {
17121715
new_val = Some((def.def_id(), trait_ref.clone()));
17131716
new_id = Some(def.def_id());
17141717
}
1715-
visit::walk_trait_ref(self, trait_ref);
17161718
}
17171719
let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
17181720
let result = f(self, new_id);
@@ -1740,60 +1742,66 @@ impl<'a> Resolver<'a> {
17401742
impl_items: &[ImplItem]) {
17411743
// If applicable, create a rib for the type parameters.
17421744
self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind), |this| {
1743-
// Resolve the type parameters.
1744-
this.visit_generics(generics);
1745-
1746-
// Resolve the trait reference, if necessary.
1747-
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
1748-
// Resolve the self type.
1749-
this.visit_ty(self_type);
1750-
1751-
let item_def_id = this.definitions.local_def_id(item_id);
1752-
this.with_self_rib(Def::SelfTy(trait_id, Some(item_def_id)), |this| {
1753-
this.with_current_self_type(self_type, |this| {
1754-
for impl_item in impl_items {
1755-
this.check_proc_macro_attrs(&impl_item.attrs);
1756-
this.resolve_visibility(&impl_item.vis);
1757-
match impl_item.node {
1758-
ImplItemKind::Const(..) => {
1759-
// If this is a trait impl, ensure the const
1760-
// exists in trait
1761-
this.check_trait_item(impl_item.ident.name,
1762-
ValueNS,
1763-
impl_item.span,
1764-
|n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
1765-
visit::walk_impl_item(this, impl_item);
1766-
}
1767-
ImplItemKind::Method(ref sig, _) => {
1768-
// If this is a trait impl, ensure the method
1769-
// exists in trait
1770-
this.check_trait_item(impl_item.ident.name,
1771-
ValueNS,
1772-
impl_item.span,
1773-
|n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
1774-
1775-
// We also need a new scope for the method-
1776-
// specific type parameters.
1777-
let type_parameters =
1778-
HasTypeParameters(&sig.generics,
1779-
MethodRibKind(!sig.decl.has_self()));
1780-
this.with_type_parameter_rib(type_parameters, |this| {
1745+
// Dummy self type for better errors if `Self` is used in the trait path.
1746+
this.with_self_rib(Def::SelfTy(None, None), |this| {
1747+
// Resolve the trait reference, if necessary.
1748+
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
1749+
let item_def_id = this.definitions.local_def_id(item_id);
1750+
this.with_self_rib(Def::SelfTy(trait_id, Some(item_def_id)), |this| {
1751+
if let Some(trait_ref) = opt_trait_reference.as_ref() {
1752+
// Resolve type arguments in trait path
1753+
visit::walk_trait_ref(this, trait_ref);
1754+
}
1755+
// Resolve the self type.
1756+
this.visit_ty(self_type);
1757+
// Resolve the type parameters.
1758+
this.visit_generics(generics);
1759+
this.with_current_self_type(self_type, |this| {
1760+
for impl_item in impl_items {
1761+
this.check_proc_macro_attrs(&impl_item.attrs);
1762+
this.resolve_visibility(&impl_item.vis);
1763+
match impl_item.node {
1764+
ImplItemKind::Const(..) => {
1765+
// If this is a trait impl, ensure the const
1766+
// exists in trait
1767+
this.check_trait_item(impl_item.ident.name,
1768+
ValueNS,
1769+
impl_item.span,
1770+
|n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
17811771
visit::walk_impl_item(this, impl_item);
1782-
});
1783-
}
1784-
ImplItemKind::Type(ref ty) => {
1785-
// If this is a trait impl, ensure the type
1786-
// exists in trait
1787-
this.check_trait_item(impl_item.ident.name,
1788-
TypeNS,
1789-
impl_item.span,
1790-
|n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
1791-
1792-
this.visit_ty(ty);
1772+
}
1773+
ImplItemKind::Method(ref sig, _) => {
1774+
// If this is a trait impl, ensure the method
1775+
// exists in trait
1776+
this.check_trait_item(impl_item.ident.name,
1777+
ValueNS,
1778+
impl_item.span,
1779+
|n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
1780+
1781+
// We also need a new scope for the method-
1782+
// specific type parameters.
1783+
let type_parameters =
1784+
HasTypeParameters(&sig.generics,
1785+
MethodRibKind(!sig.decl.has_self()));
1786+
this.with_type_parameter_rib(type_parameters, |this| {
1787+
visit::walk_impl_item(this, impl_item);
1788+
});
1789+
}
1790+
ImplItemKind::Type(ref ty) => {
1791+
// If this is a trait impl, ensure the type
1792+
// exists in trait
1793+
this.check_trait_item(impl_item.ident.name,
1794+
TypeNS,
1795+
impl_item.span,
1796+
|n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
1797+
1798+
this.visit_ty(ty);
1799+
}
1800+
ImplItemKind::Macro(_) =>
1801+
panic!("unexpanded macro in resolve!"),
17931802
}
1794-
ImplItemKind::Macro(_) => panic!("unexpanded macro in resolve!"),
17951803
}
1796-
}
1804+
});
17971805
});
17981806
});
17991807
});

Diff for: src/librustc_typeck/astconv.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -1401,11 +1401,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
14011401

14021402
assert_eq!(opt_self_ty, None);
14031403
tcx.prohibit_type_params(&path.segments);
1404-
let ty = tcx.item_type(def_id);
1405-
if let Some(free_substs) = self.get_free_substs() {
1406-
ty.subst(tcx, free_substs)
1404+
1405+
// FIXME: Self type is not always computed when we are here because type parameter
1406+
// bounds may affect Self type and have to be converted before it.
1407+
let ty = if def_id.is_local() {
1408+
tcx.item_types.borrow().get(&def_id).cloned()
14071409
} else {
1408-
ty
1410+
Some(tcx.item_type(def_id))
1411+
};
1412+
if let Some(ty) = ty {
1413+
if let Some(free_substs) = self.get_free_substs() {
1414+
ty.subst(tcx, free_substs)
1415+
} else {
1416+
ty
1417+
}
1418+
} else {
1419+
tcx.sess.span_err(span, "`Self` type is used before it's determined");
1420+
tcx.types.err
14091421
}
14101422
}
14111423
Def::SelfTy(Some(_), None) => {

Diff for: src/test/compile-fail/resolve-self-in-impl-2.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2016 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+
struct S<T = u8>(T);
12+
trait Tr<T = u8> {}
13+
14+
impl Self for S {} //~ ERROR expected trait, found self type `Self`
15+
impl Self::N for S {} //~ ERROR cannot find trait `N` in `Self`
16+
17+
fn main() {}

Diff for: src/test/compile-fail/resolve-self-in-impl.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2016 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+
struct S<T = u8>(T);
12+
trait Tr<T = u8> {}
13+
14+
impl Tr<Self> for S {} // OK
15+
16+
// FIXME: `Self` cannot be used in bounds because it depends on bounds itself.
17+
impl<T: Tr<Self>> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
18+
impl<T = Self> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
19+
impl Tr for S where Self: Copy {} //~ ERROR `Self` type is used before it's determined
20+
impl Tr for S where S<Self>: Copy {} //~ ERROR `Self` type is used before it's determined
21+
impl Tr for Self {} //~ ERROR `Self` type is used before it's determined
22+
impl Tr for S<Self> {} //~ ERROR `Self` type is used before it's determined
23+
impl Self {} //~ ERROR `Self` type is used before it's determined
24+
impl S<Self> {} //~ ERROR `Self` type is used before it's determined
25+
26+
fn main() {}

Diff for: src/test/ui/resolve/issue-23305.stderr

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
1-
error[E0411]: cannot find type `Self` in this scope
1+
error: `Self` type is used before it's determined
22
--> $DIR/issue-23305.rs:15:12
33
|
44
15 | impl ToNbt<Self> {}
5-
| ^^^^ `Self` is only available in traits and impls
6-
7-
error[E0038]: the trait `ToNbt` cannot be made into an object
8-
--> $DIR/issue-23305.rs:15:6
9-
|
10-
15 | impl ToNbt<Self> {}
11-
| ^^^^^^^^^^^ the trait `ToNbt` cannot be made into an object
12-
|
13-
= note: method `new` has no receiver
5+
| ^^^^
146

157
error: aborting due to previous error
168

0 commit comments

Comments
 (0)