Skip to content

Commit bd36778

Browse files
committed
Add query for on_unimplemented resolutions
1 parent 82cc990 commit bd36778

File tree

9 files changed

+111
-35
lines changed

9 files changed

+111
-35
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,8 @@ define_dep_nodes!( <'tcx>
611611
[] HasCloneClosures(CrateNum),
612612
[] HasCopyClosures(CrateNum),
613613

614+
[] MatchesResolutions(DefId),
615+
614616
// This query is not expected to have inputs -- as a result, it's
615617
// not a good candidate for "replay" because it's essentially a
616618
// pure function of its input (and hence the expectation is that

src/librustc/traits/on_unimplemented.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use ty::{self, TyCtxt};
1515
use util::common::ErrorReported;
1616
use util::nodemap::FxHashMap;
1717

18-
use syntax::ast::{MetaItem, NestedMetaItem};
18+
use syntax::ast::{LitKind, MetaItem, NestedMetaItem};
1919
use syntax::attr;
2020
use syntax_pos::Span;
2121
use syntax_pos::symbol::InternedString;
@@ -83,7 +83,55 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
8383
"invalid on-clause here",
8484
None)
8585
})?;
86-
attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true);
86+
attr::eval_condition_with_custom_list_handler(
87+
cond, &tcx.sess.parse_sess, &mut |_| true,
88+
&mut |attribute, nested_list| {
89+
if attribute.name != "matches" {
90+
return None;
91+
}
92+
93+
let matches_resolutions = tcx.matches_resolutions(trait_def_id)
94+
.expect(&format!(
95+
"No matches resolutions found for trait {:?}", trait_def_id));
96+
97+
let mut bound_name = None;
98+
let mut self_name = None;
99+
100+
for nested_item in nested_list {
101+
if let Some(lit) = nested_item.literal() {
102+
if let LitKind::Str(name, _) = lit.node {
103+
// This is a trait path like
104+
// matches("IsNoneError", Self="T")
105+
// ^^^^^^^^^^^
106+
bound_name = Some(name);
107+
}
108+
} else if let Some((key, lit)) = nested_item.name_value_literal() {
109+
if key == "Self" {
110+
if let LitKind::Str(name, _) = lit.node {
111+
// This is a self type specification like
112+
// matches("IsNoneError", Self="T")
113+
// ^^^^^^^^
114+
self_name = Some(name);
115+
}
116+
}
117+
}
118+
}
119+
120+
let bound_name = bound_name.expect("matches clause should have a bound literal");
121+
let self_name = self_name.expect("matches clause should have a self KV-pair");
122+
123+
let _bound_id = matches_resolutions.iter()
124+
.find(|res| res.0 == bound_name)
125+
.expect("no resolution for matches bound");
126+
127+
let _self_id = matches_resolutions.iter()
128+
.find(|res| res.0 == self_name)
129+
.expect("no resolution for self found");
130+
131+
// TODO: use these ids to check if the self type implements the bound
132+
133+
Some(true)
134+
});
87135
Some(cond.clone())
88136
};
89137

src/librustc/ty/context.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,8 @@ pub struct GlobalCtxt<'tcx> {
889889

890890
maybe_unused_extern_crates: Vec<(DefId, Span)>,
891891

892+
id_to_matches_resolutions: FxHashMap<DefId, Rc<Vec<(Name, DefId)>>>,
893+
892894
// Internal cache for metadata decoding. No need to track deps on this.
893895
pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
894896

@@ -1164,6 +1166,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
11641166
.into_iter()
11651167
.map(|(id, sp)| (hir.local_def_id(id), sp))
11661168
.collect(),
1169+
id_to_matches_resolutions:
1170+
resolutions.id_to_matches_resolutions
1171+
.into_iter()
1172+
.map(|(id, matches)| (id, Rc::new(matches)))
1173+
.collect(),
11671174
hir,
11681175
def_path_hash_to_def_id,
11691176
maps: maps::Maps::new(providers),
@@ -2252,6 +2259,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
22522259
// FIXME(#44234) - almost all of these queries have no sub-queries and
22532260
// therefore no actual inputs, they're just reading tables calculated in
22542261
// resolve! Does this work? Unsure! That's what the issue is about
2262+
providers.matches_resolutions = |tcx, id| tcx.gcx.id_to_matches_resolutions.get(&id).cloned();
22552263
providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id).cloned();
22562264
providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).cloned();
22572265
providers.named_region_map = |tcx, id| tcx.gcx.named_region_map.defs.get(&id).cloned();

src/librustc/ty/maps/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,9 @@ define_maps! { <'tcx>
345345
[] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool,
346346
[] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool,
347347

348+
// Resolutions for rustc_on_unimplemented "matches" clause
349+
[] fn matches_resolutions: MatchesResolutions(DefId) -> Option<Rc<Vec<(ast::Name, DefId)>>>,
350+
348351
// Erases regions from `ty` to yield a new type.
349352
// Normally you would just use `tcx.erase_regions(&value)`,
350353
// however, which uses this query as a kind of cache.

src/librustc/ty/maps/plumbing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
758758
DepKind::SpecializationGraph => { force!(specialization_graph_of, def_id!()); }
759759
DepKind::ObjectSafety => { force!(is_object_safe, def_id!()); }
760760
DepKind::TraitImpls => { force!(trait_impls_of, def_id!()); }
761+
DepKind::MatchesResolutions => { force!(matches_resolutions, def_id!()); }
761762

762763
DepKind::ParamEnv => { force!(param_env, def_id!()); }
763764
DepKind::DescribeDef => { force!(describe_def, def_id!()); }

src/librustc/ty/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ pub struct Resolutions {
133133
pub trait_map: TraitMap,
134134
pub maybe_unused_trait_imports: NodeSet,
135135
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
136+
pub id_to_matches_resolutions: DefIdMap<Vec<(Name, DefId)>>,
136137
pub export_map: ExportMap,
137138
}
138139

src/librustc_driver/driver.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
903903
trait_map: resolver.trait_map,
904904
maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
905905
maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
906+
id_to_matches_resolutions: resolver.id_to_matches_resolutions,
906907
},
907908
hir_forest,
908909
})

src/librustc_resolve/lib.rs

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics};
5656
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
5757
use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
5858
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
59-
use syntax::ast::{Attribute, LitKind, MetaItemKind, NestedMetaItem, PathSegment};
59+
use syntax::ast::{Attribute, LitKind, NestedMetaItem, PathSegment};
6060
use syntax::feature_gate::{feature_err, emit_feature_err, GateIssue};
6161

6262
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
@@ -3703,49 +3703,46 @@ impl<'a> Resolver<'a> {
37033703
let mut matches = Vec::new();
37043704
for attr in attrs {
37053705
self.resolve_matches(
3706-
node_id, &mut matches, attr.meta_item_list().as_ref().map(|x| x.as_ref()));
3706+
node_id, false, &mut matches, attr.meta_item_list().as_ref().map(|x| x.as_ref()));
37073707
}
37083708
let def_id = self.definitions.local_def_id(node_id);
37093709
self.id_to_matches_resolutions.insert(def_id, matches);
37103710
}
37113711

37123712
fn resolve_matches(&mut self,
37133713
node_id: NodeId,
3714+
seen_on_unimplemented: bool,
37143715
matches: &mut Vec<(Name, DefId)>,
37153716
meta_item_list: Option<&[NestedMetaItem]>)
37163717
{
37173718
for item in meta_item_list.into_iter().flat_map(|x| x) {
37183719
// Run recursively
3719-
self.resolve_matches(node_id, matches, item.meta_item_list());
3720+
let seen_on_unimplemented = seen_on_unimplemented || item.check_name("rustc_on_unimplemented");
3721+
self.resolve_matches(node_id, seen_on_unimplemented, matches, item.meta_item_list());
37203722

3721-
// Check for "matches"
3722-
if item.check_name("matches") {
3723+
// Check for "matches" inside of "rustc_on_unimplemented" attributes
3724+
if seen_on_unimplemented && item.check_name("matches") {
37233725
for nested_item in item.meta_item_list().into_iter().flat_map(|x| x) {
3724-
if let Some(meta_item) = nested_item.meta_item() {
3725-
let (to_resolve, path_source, path_span) = match meta_item.node {
3726-
MetaItemKind::Word => {
3727-
// This is a trait path like
3726+
let mut to_resolve = None;
3727+
if let Some(lit) = nested_item.literal() {
3728+
if let LitKind::Str(name, _) = lit.node {
3729+
// This is a trait path like
3730+
// matches("IsNoneError", Self="T")
3731+
// ^^^^^^^^^^^
3732+
to_resolve = Some((name, PathSource::Trait, lit.span));
3733+
}
3734+
} else if let Some((key, lit)) = nested_item.name_value_literal() {
3735+
if key == "Self" {
3736+
if let LitKind::Str(name, _) = lit.node {
3737+
// This is a self type specification like
37283738
// matches("IsNoneError", Self="T")
3729-
// ^^^^^^^^^^^
3730-
(meta_item.name, PathSource::Trait, meta_item.span)
3731-
}
3732-
MetaItemKind::NameValue(ref lit) => {
3733-
if let LitKind::Str(symbol, _) = lit.node {
3734-
if meta_item.name == "Self" {
3735-
// This is a self type specification like
3736-
// matches("IsNoneError", Self="T")
3737-
// ^^^^^^^^
3738-
(symbol, PathSource::Type, lit.span)
3739-
} else {
3740-
continue;
3741-
}
3742-
} else {
3743-
continue
3744-
}
3739+
// ^^^^^^^^
3740+
to_resolve = Some((name, PathSource::Type, lit.span));
37453741
}
3746-
MetaItemKind::List(_) => continue,
3747-
};
3742+
}
3743+
}
37483744

3745+
if let Some((name, path_source, span)) = to_resolve {
37493746
// TODO(cramertj) this will only work for single-part paths such as
37503747
// `T` or `IsNoneError`-- it won't work for `::mymod::IsNoneError`
37513748
// or `IsNoneError<T>`-- I'm not sure how best to handle this.
@@ -3755,17 +3752,17 @@ impl<'a> Resolver<'a> {
37553752
node_id,
37563753
None,
37573754
&Path {
3758-
span: path_span,
3755+
span: span,
37593756
segments: vec![PathSegment {
3760-
identifier: to_resolve.to_ident(),
3761-
span: path_span,
3757+
identifier: name.to_ident(),
3758+
span: span,
37623759
parameters: None,
37633760
}],
37643761
},
37653762
path_source
37663763
);
37673764

3768-
matches.push((to_resolve, resolution.base_def().def_id()));
3765+
matches.push((name, resolution.base_def().def_id()));
37693766
}
37703767
}
37713768
}

src/libsyntax/attr.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,17 @@ pub fn cfg_matches(cfg: &ast::MetaItem, sess: &ParseSess, features: Option<&Feat
588588
pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
589589
-> bool
590590
where F: FnMut(&ast::MetaItem) -> bool
591+
{
592+
eval_condition_with_custom_list_handler(cfg, sess, eval, &mut |_, _| None)
593+
}
594+
595+
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
596+
/// evaluate individual items.
597+
pub fn eval_condition_with_custom_list_handler<F, P>(
598+
cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F, custom_list_handler: &mut P)
599+
-> bool
600+
where F: FnMut(&ast::MetaItem) -> bool,
601+
P: FnMut(&ast::MetaItem, &[NestedMetaItem]) -> Option<bool>,
591602
{
592603
match cfg.node {
593604
ast::MetaItemKind::List(ref mis) => {
@@ -616,8 +627,12 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
616627
!eval_condition(mis[0].meta_item().unwrap(), sess, eval)
617628
},
618629
p => {
619-
span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p);
620-
false
630+
if let Some(res) = custom_list_handler(cfg, mis) {
631+
res
632+
} else {
633+
span_err!(sess.span_diagnostic, cfg.span, E0537, "invalid predicate `{}`", p);
634+
false
635+
}
621636
}
622637
}
623638
},

0 commit comments

Comments
 (0)