9
9
// except according to those terms.
10
10
11
11
use hir:: def_id:: DefId ;
12
- use ty:: { self , Ty , TypeFoldable , Substs , TyCtxt } ;
13
- use ty:: subst:: Kind ;
12
+ use ty:: { self , Ty , TypeFoldable , Substs , TyCtxt , AssociatedKind , AssociatedItemContainer } ;
13
+ use ty:: subst:: { Kind , Subst } ;
14
14
use traits;
15
15
use syntax:: abi:: Abi ;
16
16
use util:: ppaux;
17
17
18
18
use std:: fmt;
19
19
20
+ use syntax_pos:: { BytePos , Span } ;
21
+ use syntax:: ext:: hygiene:: SyntaxContext ;
22
+ use hir:: map:: Node :: NodeTraitItem ;
23
+ use hir;
24
+
20
25
#[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
21
26
pub struct Instance < ' tcx > {
22
27
pub def : InstanceDef < ' tcx > ,
@@ -260,6 +265,13 @@ fn resolve_associated_item<'a, 'tcx>(
260
265
traits:: VtableImpl ( impl_data) => {
261
266
let ( def_id, substs) = traits:: find_associated_item (
262
267
tcx, trait_item, rcvr_substs, & impl_data) ;
268
+
269
+ check_unimplemented_trait_item ( tcx,
270
+ impl_data. impl_def_id ,
271
+ def_id,
272
+ trait_id,
273
+ trait_item) ;
274
+
263
275
let substs = tcx. erase_regions ( & substs) ;
264
276
Some ( ty:: Instance :: new ( def_id, substs) )
265
277
}
@@ -363,3 +375,108 @@ fn fn_once_adapter_instance<'a, 'tcx>(
363
375
debug ! ( "fn_once_adapter_shim: self_ty={:?} sig={:?}" , self_ty, sig) ;
364
376
Instance { def, substs }
365
377
}
378
+
379
+ fn check_unimplemented_trait_item < ' a , ' tcx > (
380
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
381
+ impl_def_id : DefId ,
382
+ trait_item_def_id : DefId ,
383
+ trait_id : DefId ,
384
+ trait_item : & ty:: AssociatedItem )
385
+ {
386
+ // if trait_item_def_id is a trait item and it doesn't have a default trait implementation
387
+ // the resolution has found an unimplemented trait item inside a default impl
388
+ if tcx. impl_is_default ( impl_def_id) {
389
+ let is_unimplemented_trait_item = match tcx. hir . as_local_node_id ( trait_item_def_id) {
390
+ Some ( node_id) =>
391
+ match tcx. hir . find ( node_id) {
392
+ Some ( NodeTraitItem ( item) ) => {
393
+ if let hir:: TraitItemKind :: Method ( _,
394
+ hir:: TraitMethod :: Provided ( _) )
395
+ = item. node {
396
+ false
397
+ } else {
398
+ true
399
+ }
400
+ } ,
401
+ _ => false
402
+ }
403
+ None => {
404
+ let item = tcx. global_tcx ( ) . associated_item ( trait_item_def_id) ;
405
+ match item. kind {
406
+ AssociatedKind :: Method => match item. container {
407
+ AssociatedItemContainer :: TraitContainer ( _) => {
408
+ !item. defaultness . has_value ( )
409
+ }
410
+ _ => false
411
+ }
412
+ _ => false
413
+ }
414
+ }
415
+ } ;
416
+
417
+ if is_unimplemented_trait_item {
418
+ let mut err = tcx. sess . struct_err ( & format ! ( "the trait method `{}` \
419
+ is not implemented",
420
+ trait_item. name) ) ;
421
+
422
+ let mut help_messages = Vec :: new ( ) ;
423
+ help_messages. push (
424
+ if impl_def_id. is_local ( ) {
425
+ let item = tcx. hir
426
+ . expect_item (
427
+ tcx. hir
428
+ . as_local_node_id ( impl_def_id) . unwrap ( )
429
+ ) ;
430
+ ( item. span , format ! ( "implement it inside this `default impl`" ) )
431
+ } else {
432
+ ( Span :: new (
433
+ BytePos ( 0 ) ,
434
+ BytePos ( 0 ) ,
435
+ SyntaxContext :: empty ( )
436
+ ) ,
437
+ format ! ( "implement it inside the {} `default impl`" ,
438
+ tcx. item_path_str( impl_def_id) ) )
439
+ }
440
+ ) ;
441
+
442
+ help_messages. push (
443
+ if trait_id. is_local ( ) {
444
+ let trait_item = tcx. hir
445
+ . expect_item (
446
+ tcx. hir
447
+ . as_local_node_id ( trait_id) . unwrap ( )
448
+ ) ;
449
+ ( trait_item. span , format ! ( "provide a default method implementation \
450
+ inside this `trait`") )
451
+ } else {
452
+ ( Span :: new (
453
+ BytePos ( 0 ) ,
454
+ BytePos ( 0 ) ,
455
+ SyntaxContext :: empty ( )
456
+ ) ,
457
+ format ! ( "provide a default method implementation \
458
+ inside the {} `trait`",
459
+ tcx. item_path_str( trait_id) ) )
460
+ }
461
+ ) ;
462
+
463
+ help_messages. sort_by ( |& ( a, _) , & ( b, _) | a. partial_cmp ( & b) . unwrap ( ) ) ;
464
+
465
+ let mut cnjs = vec ! [ "or " , "either " ] ;
466
+ help_messages. iter ( ) . for_each ( |& ( span, ref msg) | {
467
+ let mut help_msg = String :: from ( cnjs. pop ( ) . unwrap_or ( "" ) ) ;
468
+ help_msg. push_str ( & msg) ;
469
+
470
+ if span. data ( ) . lo == BytePos ( 0 ) && span. data ( ) . hi == BytePos ( 0 ) {
471
+ err. help ( & help_msg) ;
472
+ } else {
473
+ err. span_help ( span, & help_msg) ;
474
+ }
475
+ } ) ;
476
+
477
+ err. note ( & format ! ( "a `default impl` doesn't need to include all \
478
+ items from the trait") ) ;
479
+ err. emit ( ) ;
480
+ }
481
+ }
482
+ }
0 commit comments