@@ -428,6 +428,256 @@ match 5u32 {
428
428
```
429
429
"## ,
430
430
431
+ E0038 : r####"
432
+
433
+ Trait objects like `Box<Trait>`, can only be constructed when certain
434
+ requirements are obeyed by the trait in question.
435
+
436
+ Trait objects are a form of dynamic dispatch and use dynamically sized types.
437
+ So, for a given trait `Trait`, when `Trait` is treated as a type, as in
438
+ `Box<Trait>`, the inner type is "unsized". In such cases the boxed pointer is a
439
+ "fat pointer" and contains an extra pointer to a method table for dynamic
440
+ dispatch. This design mandates some restrictions on the types of traits that are
441
+ allowed to be used in trait objects, which are collectively termed as "object
442
+ safety" rules.
443
+
444
+ Attempting to create a trait object for a non object-safe trait will trigger
445
+ this error.
446
+
447
+
448
+ There are various rules:
449
+
450
+ ### The trait cannot require `Self: Sized`
451
+
452
+ When `Trait` is treated as a type, the type does not implement the special
453
+ `Sized` trait, because the type does not have a known size at compile time and
454
+ can only be accessed behind a pointer. Thus, if we have a trait like the
455
+ following:
456
+
457
+ ```
458
+ trait Foo where Self: Sized {
459
+
460
+ }
461
+ ```
462
+
463
+ we cannot create an object of type `Box<Foo>` or `&Foo` since in this case
464
+ `Self` would not be `Sized`.
465
+
466
+ Generally `Self : Sized` is used to indicate that the trait should not be used
467
+ as a trait object. If the trait comes from your own crate, consider removing
468
+ this restriction.
469
+
470
+ ### Method references the `Self` type in its arguments or return type
471
+
472
+ This happens when a trait has a method like the following:
473
+
474
+ ```
475
+ trait Trait {
476
+ fn foo(&self) -> Self;
477
+ }
478
+ impl Trait for String {
479
+ fn foo(&self) -> Self {
480
+ "hi".to_owned()
481
+ }
482
+ }
483
+
484
+ impl Trait for u8 {
485
+ fn foo(&self) -> Self {
486
+ 1
487
+ }
488
+ }
489
+ ```
490
+
491
+ In such a case, the compiler cannot predict the return type of `foo()` in a case
492
+ like the following:
493
+
494
+ ```
495
+ fn call_foo(x: Box<Trait>) {
496
+ let y = x.foo(); // What type is y?
497
+ // ...
498
+ }
499
+ ```
500
+
501
+ If the offending method isn't actually being called on the trait object, you can
502
+ add a `where Self: Sized` bound on the method:
503
+
504
+ ```
505
+ trait Trait {
506
+ fn foo(&self) -> Self where Self: Sized;
507
+ // more functions
508
+ }
509
+ ```
510
+
511
+ Now, `foo()` can no longer be called on the trait object, but you will be
512
+ allowed to call other trait methods and construct the trait objects. With such a
513
+ bound, one can still call `foo()` on types implementing that trait that aren't
514
+ behind trait objects.
515
+
516
+ ### Method has generic type parameters
517
+
518
+ As mentioned before, trait objects contain pointers to method tables. So, if we
519
+ have
520
+
521
+ ```
522
+ trait Trait {
523
+ fn foo(&self);
524
+ }
525
+ impl Trait for String {
526
+ fn foo(&self) {
527
+ // implementation 1
528
+ }
529
+ }
530
+ impl Trait for u8 {
531
+ fn foo(&self) {
532
+ // implementation 2
533
+ }
534
+ }
535
+ // ...
536
+ ```
537
+
538
+ at compile time a table of all implementations of `Trait`, containing pointers
539
+ to the implementation of `foo()` would be generated.
540
+
541
+ This works fine, but when we the method gains generic parameters, we can have a
542
+ problem.
543
+
544
+ Usually, generic parameters get _monomorphized_. For example, if I have
545
+
546
+ ```
547
+ fn foo<T>(x: T) {
548
+ // ...
549
+ }
550
+ ```
551
+
552
+ the machine code for `foo::<u8>()`, `foo::<bool>()`, `foo::<String>()`, or any
553
+ other type substitution is different. Hence the compiler generates the
554
+ implementation on-demand. If you call `foo()` with a `bool` parameter, the
555
+ compiler will only generate code for `foo::<bool>()`. When we have additional
556
+ type parameters, the number of monomorphized implementations the compiler
557
+ generates does not grow drastically, since the compiler will only generate an
558
+ implementation if the function is called with hard substitutions.
559
+
560
+ However, with trait objects we have to make a table containing _every object
561
+ that implements the trait_. Now, if it has type parameters, we need to add
562
+ implementations for every type that implements the trait, bloating the table
563
+ quickly.
564
+
565
+ For example, with
566
+
567
+ ```
568
+ trait Trait {
569
+ fn foo<T>(&self, on: T);
570
+ // more methods
571
+ }
572
+ impl Trait for String {
573
+ fn foo<T>(&self, on: T) {
574
+ // implementation 1
575
+ }
576
+ }
577
+ impl Trait for u8 {
578
+ fn foo<T>(&self, on: T) {
579
+ // implementation 2
580
+ }
581
+ }
582
+ // 8 more implementations
583
+ ```
584
+
585
+ Now, if I have the following code:
586
+
587
+ ```
588
+ fn call_foo(thing: Box<Trait>) {
589
+ thing.foo(true); // this could be any one of the 8 types above
590
+ thing.foo(1);
591
+ thing.foo("hello");
592
+ }
593
+ ```
594
+
595
+ we don't just need to create a table of all implementations of all methods of
596
+ `Trait`, we need to create a table of all implementations of `foo()`, _for each
597
+ different type fed to `foo()`_. In this case this turns out to be (10 types
598
+ implementing `Trait`)*(3 types being fed to `foo()`) = 30 implementations!
599
+
600
+ With real world traits these numbers can grow drastically.
601
+
602
+ To fix this, it is suggested to use a `where Self: Sized` bound similar to the
603
+ fix for the sub-error above if you do not intend to call the method with type
604
+ parameters:
605
+
606
+ ```
607
+ trait Trait {
608
+ fn foo<T>(&self, on: T) where Self: Sized;
609
+ // more methods
610
+ }
611
+ ```
612
+
613
+ If this is not an option, consider replacing the type parameter with another
614
+ trait object (e.g. if `T: OtherTrait`, use `on: Box<OtherTrait>`). If the number
615
+ of types you intend to feed to this method is limited, consider manually listing
616
+ out the methods of different types.
617
+
618
+ ### Method has no receiver
619
+
620
+ Methods that do not take a `self` parameter can't be called since there won't be
621
+ a way to get a pointer to the method table for them
622
+
623
+ ```
624
+ trait Foo {
625
+ fn foo() -> u8;
626
+ }
627
+ ```
628
+
629
+ This could be called as `<Foo as Foo>::foo()`, which would not be able to pick
630
+ an implementation.
631
+
632
+ Adding a `Self: Sized` bound to these methods will generally make this compile.
633
+
634
+
635
+ ```
636
+ trait Foo {
637
+ fn foo() -> u8 where Self: Sized;
638
+ }
639
+ ```
640
+
641
+ ### The trait cannot use `Self` as a type parameter in the supertrait listing
642
+
643
+ This is similar to the second sub-error, but subtler. It happens in situations
644
+ like the following:
645
+
646
+ ```
647
+ trait Super<A> {}
648
+
649
+ trait Trait: Super<Self> {
650
+ }
651
+
652
+ struct Foo;
653
+
654
+ impl Super<Foo> for Foo{}
655
+
656
+ impl Trait for Foo {}
657
+ ```
658
+
659
+ Here, the supertrait might have methods as follows:
660
+
661
+ ```
662
+ trait Super<A> {
663
+ fn get_a(&self) -> A; // note that this is object safe!
664
+ }
665
+ ```
666
+
667
+ If the trait `Foo` was deriving from something like `Super<String>` or
668
+ `Super<T>` (where `Foo` itself is `Foo<T>`), this is okay, because given a type
669
+ `get_a()` will definitely return an object of that type.
670
+
671
+ However, if it derives from `Super<Self>`, the method `get_a()` would return an
672
+ object of unknown type when called on the function, _even though `Super` is
673
+ object safe_. `Self` type parameters let us make object safe traits no longer
674
+ safe, so they are forbidden when specifying supertraits.
675
+
676
+ There's no easy fix for this, generally code will need to be refactored so that
677
+ you no longer need to derive from `Super<Self>`.
678
+
679
+ "#### ,
680
+
431
681
E0079 : r##"
432
682
Enum variants which contain no data can be given a custom integer
433
683
representation. This error indicates that the value provided is not an
@@ -1295,7 +1545,6 @@ contain references (with a maximum lifetime of `'a`).
1295
1545
1296
1546
register_diagnostics ! {
1297
1547
// E0006 // merged with E0005
1298
- E0038 ,
1299
1548
// E0134,
1300
1549
// E0135,
1301
1550
E0136 ,
0 commit comments