Science, Faculty of
Computer Science, Department of
DSpace
UBCV
Milewski, Jonatan
2015-12-01T03:19:12
2015
Master of Science - MSc
University of British Columbia
Rust is a new systems programming language designed with a focus on bare metal performance, safe concurrency and memory safety. It features a robust abstraction mechanism in the form of traits, which provide static overloading and dynamic dispatch. In this thesis, we present MiniRust—a formal model of a subset of Rust. The model focuses on the trait system and includes some advanced features of traits such as associated types and trait objects. In particular, we discuss the notion of object safety—the suitability of a particular trait for creating trait objects—and we formally determine very general conditions under which it can be guaranteed. To represent the runtime semantics of MiniRust programs, we develop an explicitly-typed internal language RustIn, for which we prove type safety, and we show that well-typed MiniRust programs can be translated to well-typed RustIn programs. Finally, we adapt the informally-described Rust trait coherence rules to our model and we show that
they are sufficient to ensure that overloads are always well-determined, even in the presence of library extensions.
https://circle.library.ubc.ca/rest/handle/2429/55609?expand=metadata
Formalizing Rust TraitsbyJonatan MilewskiB. Sc., McGill University, 2013A THESIS SUBMITTED IN PARTIAL FULFILLMENTOF THE REQUIREMENTS FOR THE DEGREE OFMaster of ScienceinTHE FACULTY OF GRADUATE AND POSTDOCTORAL STUDIES(Computer Science)The University of British Columbia(Vancouver)November 2015© Jonatan Milewski, 2015AbstractRust is a new systems programming language designed with a focus on bare metal perfor-mance, safe concurrency and memory safety. It features a robust abstraction mechanism inthe form of traits, which provide static overloading and dynamic dispatch. In this thesis, wepresent MiniRust—a formal model of a subset of Rust. The model focuses on the trait systemand includes some advanced features of traits such as associated types and trait objects. Inparticular, we discuss the notion of object safety—the suitability of a particular trait for cre-ating trait objects—and we formally determine very general conditions under which it canbe guaranteed. To represent the runtime semantics of MiniRust programs, we develop anexplicitly-typed internal language RustIn, for which we prove type safety, and we show thatwell-typed MiniRust programs can be translated to well-typed RustIn programs. Finally, weadapt the informally-described Rust trait coherence rules to our model and we show thatthey are sufficient to ensure that overloads are always well-determined, even in the presenceof library extensions.iiPrefaceThis thesis is original, unpublished, independent work by the author, Jonatan Milewski.iiiTable of ContentsAbstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iiPreface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . iiiTable of Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ivList of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viiiAcknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Traits in Rust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.1 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 Structs and pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.3 Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.4 Associated functions & UFCS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.5 Supertraits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.6 Multi-parameter traits & associated types . . . . . . . . . . . . . . . . . . . . . . 102.7 Trait objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 NanoRust: a language with traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.1 Some syntactic conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.2 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173.2.1 Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173.2.2 Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.2.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203.2.4 Polymorphic types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203.2.5 Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.2.6 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21iv3.3 Well-formedness and constraint entailment . . . . . . . . . . . . . . . . . . . . . 223.4 Well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243.5 Well-typed items & programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.5.1 Well-typed traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.5.2 Well-typed impls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284 MicroRust: NanoRust with associated types . . . . . . . . . . . . . . . . . . . . . 294.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294.1.1 Associated types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294.1.2 Type equality constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304.2 Typing rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314.2.1 Well-formedness judgments . . . . . . . . . . . . . . . . . . . . . . . . . . 314.2.2 Constraint entailment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334.2.3 Well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334.2.4 Well-typed items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 MiniRust: MicroRust with trait objects . . . . . . . . . . . . . . . . . . . . . . . . 375.1 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375.1.1 Trait objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375.1.2 S-types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395.1.3 Object-safe traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405.2 Type system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405.2.1 Auxiliary relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405.2.2 Well-formed types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415.2.3 Constraint entailment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415.2.4 Well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445.2.5 Well-typed items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455.3 Object-safe traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455.3.1 Typing object-safe traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485.3.2 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 RustIn: an internal language for MiniRust . . . . . . . . . . . . . . . . . . . . . . 556.1 RustIn at a glance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 556.2 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566.2.1 Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566.2.2 Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 586.2.3 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596.2.4 Coercions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59v6.2.5 Environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606.3 Type system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606.3.1 Well-typed coercions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606.3.2 Well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616.3.3 Well-typed items and programs . . . . . . . . . . . . . . . . . . . . . . . . 646.4 Operational semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656.4.1 Evaluating terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656.4.2 Evaluating lvalues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 686.4.3 Evaluating programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696.4.4 Evaluation metafunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 696.5 Type safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 727 Translating MiniRust programs to RustIn . . . . . . . . . . . . . . . . . . . . . . . 757.1 Translation at a glance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 757.2 Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 767.3 Translating types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 777.4 Translating constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 777.5 Translating terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807.6 Translating items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807.6.1 Translating traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837.6.2 Translating impls . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837.6.3 Translating object-safe traits . . . . . . . . . . . . . . . . . . . . . . . . . . 867.6.4 Translating programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 877.7 Type preservation of translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 877.8 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897.8.1 Type safety of MiniRust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 897.8.2 Monomorphization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898 Coherence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 908.1 Crates and trait coherence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 928.2 NanoRust with crates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 938.3 Trait coherence in NanoRust with crates . . . . . . . . . . . . . . . . . . . . . . . 948.4 Coherence and type safety of MiniRust . . . . . . . . . . . . . . . . . . . . . . . . 989 Limitations & future work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029.1 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029.1.1 Trait features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1029.1.2 Type safety . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102vi9.1.3 Constraint entailment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1039.2 Towards an implementation of MiniRust . . . . . . . . . . . . . . . . . . . . . . . 1039.3 Possible extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1049.4 Rust language extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10610 Related work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10811 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110Bibliography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112A Proof of type safety of RustIn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116B MiniRust translation proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156C Trait coherence proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194viiList of FiguresFigure 3.1 NanoRust: syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17Figure 3.2 NanoRust: well-formedness and constraint entailment . . . . . . . . . . . . 23Figure 3.3 NanoRust: well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25Figure 3.4 NanoRust: well-typed items and programs . . . . . . . . . . . . . . . . . . . . 26Figure 4.1 MicroRust: syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30Figure 4.2 MicroRust: well-formedness judgments . . . . . . . . . . . . . . . . . . . . . . 32Figure 4.3 MicroRust: constraint entailment . . . . . . . . . . . . . . . . . . . . . . . . . 34Figure 4.4 MicroRust: well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35Figure 4.5 MicroRust: well-typed items and programs . . . . . . . . . . . . . . . . . . . 36Figure 5.1 MiniRust: syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38Figure 5.2 MiniRust: auxiliary relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40Figure 5.3 MiniRust: well-formedness judgments . . . . . . . . . . . . . . . . . . . . . . 42Figure 5.4 MiniRust: constraint entailment . . . . . . . . . . . . . . . . . . . . . . . . . . 43Figure 5.5 MiniRust: well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44Figure 5.6 MiniRust: well-typed items and programs . . . . . . . . . . . . . . . . . . . . 46Figure 5.7 MiniRust: well-typed object-safe traits . . . . . . . . . . . . . . . . . . . . . . 49Figure 6.1 RustIn: syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57Figure 6.2 RustIn: well-typed coercions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61Figure 6.3 RustIn: well-typed coercions continued . . . . . . . . . . . . . . . . . . . . . . 62Figure 6.4 RustIn: well-typed terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63Figure 6.5 RustIn: well-typed items and programs . . . . . . . . . . . . . . . . . . . . . 64Figure 6.6 RustIn: evaluation of terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66Figure 6.7 RustIn: evaluation of terms continued . . . . . . . . . . . . . . . . . . . . . . 67Figure 6.8 RustIn: evaluation of lvalues . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68Figure 6.9 RustIn: evaluation of programs . . . . . . . . . . . . . . . . . . . . . . . . . . 69Figure 6.10 RustIn: metafunctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70viiiFigure 7.1 MiniRust: well-formedness judgments with translation . . . . . . . . . . . . 78Figure 7.2 MiniRust: constraint entailment with translation . . . . . . . . . . . . . . . 79Figure 7.3 MiniRust: well-typed terms with translation . . . . . . . . . . . . . . . . . . 81Figure 7.4 MiniRust: well-typed items with translation . . . . . . . . . . . . . . . . . . 82Figure 7.5 MiniRust: well-typed object-safe traits with translation . . . . . . . . . . . . 84Figure 7.6 MiniRust: auxiliary object-safe trait relations with translation . . . . . . . 85Figure 7.7 MiniRust: well-typed programs with translation . . . . . . . . . . . . . . . . 87Figure 7.8 MiniRust: well-formed environments with translation . . . . . . . . . . . . . 88Figure 8.1 Helper relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94ixAcknowledgmentsFirst and foremost, I would like to thank my supervisor Ron Garcia for his guidance, supportand encouragement throughout the research and writing process. His vast expertise is aninvaluable resource and his ever-positive attitude helped me stay motivated to keep going.His thorough feedback was a crucial contribution to the writing process. Also, I would like tothank Reid Holmes for providing insightful comments and suggestions on this thesis.Big thanks are also due to Niko Matsakis from Mozilla Research for his useful insightson the inner workings of Rust and to The Mozilla Corporation for funding this research. Theknowledgeable Rust community and the plethora of Rust resources stemming from it wereincredibly helpful as well.Last but not least, I would like to thank my family and friends who provided indispens-able emotional support and encouragement at times when they were most needed.xChapter 1IntroductionModern programming languages present a high degree of complexity, incorporating advancedconstructs and type system features. As such, reasoning about properties of a language,such as its static and dynamic semantics, is often quite challenging. Moreover, details of thelanguage implementation, containing numerous optimizations driven by pragmatic concerns,can make it more difficult to understand what the intended semantics are.A formal model of a programming language can abstract away its implementation detailsand allow us to focus our attention on its core. It can facilitate an in-depth study of specificaspects of the language and of the way in which they interact with one another. It can alsobe used to present complex—difficult to grasp—language features in terms of constructs andideas that are already well understood. Moreover, a formal model can serve as a base forprototyping future extensions and exploring how they would interact with the rest of thelanguage. Perhaps more importantly, the rigorous formal treatment and the availability ofvarious mathematical tools let us obtain formal proofs of certain properties of the language—in a language that strives to provide certain guarantees to the programmer, it is particularlydesirable to be able to prove that those guarantees do indeed hold. As such, a formalizationmay provide a justification for the decisions made by the language designers but it may alsoexpose gaps in the design that were overlooked.One important and commonly studied aspect of a given programming language is its typesystem. A type system can serve multiple purposes [27]. One obvious goal is to staticallydetect and report errors caused by code that would inevitably produce an undesired resultat runtime. However, the range of errors caught by the type-checker—an implementation ofthe type system—varies greatly from language to language. Another goal of a type systemis to provide the ability to create abstractions, which enable the developer to write code thatis clearer, more concise and reusable. Such abstractions may include for instance the abilityto define new datatypes and to employ generics, which allow us to write code that may be1used with values of different types. The type system can also protect such abstractions byensuring that they behave as intended.In commonly-used programming languages, the rules of the type system are seldom speci-fied formally. In an effort to gain a good understanding of the type system, users of a languagemay refer to its documentation, which often provides a rather broad view of the system. Formore detailed information, one would then have to refer to the implementation of the type-checker, where the various optimizations present in the code can make reasoning about thetype system very difficult. A formal definition of the type system can strip those imple-mentation details away and thus it facilitates reasoning about what constitutes a well-typedprogram. Combined with a model of the runtime semantics of the system, it allows us tounderstand how such programs evolve at runtime and it can be used to formally prove prop-erties such as type safety—that the type system prevents the type errors that it is designedto prevent at runtime. More generally, we may use the formal model of the type system toprove that the abstractions provided by the language act as intended.In this thesis we focus on the type system of the Rust programming language [6]. Rustis an open-source community project headed by Mozilla Research. It is also new, with ver-sion 1.0 released in May 2015, and many of its aspects have not yet been studied formally.Being a systems language, Rust is designed to be suitable for low-level programming requir-ing control, performance and predictability—properties desired in domains such as operatingsystems, embedded systems and browser engines (the browser engine Servo [8], written inRust, is its primary real-world test case). As such, its primary areas of focus are mem-ory safety, speed and concurrency. Many languages employ a runtime garbage collector toguarantee memory safety. Rust, however, does not have garbage collection, which gives theprogrammer low-level control over the memory stack and predictable runtime performance.The language relies instead on type system abstractions to ensure memory safety at compile-time without introducing runtime overhead. The relevant features of the type system includelifetimes, corresponding to regions in region-based memory management [39] [19], and theconcept of ownership [13] with move semantics, having ties to affine type systems [29]. Finally,those type system features, along with other abstractions in the language enable languagedevelopers to add data structures and functions to the standard library that allow us to writeconcurrent programs guaranteed to avoid data races.Despite being labeled a systems language, Rust includes a number of language abstrac-tions similar to those found in other higher-level languages, including algebraic data types(called enums in Rust) and pattern matching. The language also supports type inference,which lets the programmer omit some type annotations that can be inferred statically. Last,but not least, the type system provides abstractions in the form of generics and traits thatenable the programmer to write modular, reusable code. These abstractions introduce type2polymorphism in the language, where a single piece of code can be used with values of mul-tiple types [36]. While generics are associated with parametric polymorphism (where a pieceof polymorphic code behaves the same way regardless of the concrete type instantiation),traits, similar to type classes in Haskell [40], introduce another form of polymorphism calledad-hoc polymorphism or overloading, where the runtime semantics of polymorphic code varydepending on the concrete type(s) used.In a nutshell, a trait is a way to abstract over types that share the same property. Theproperty can be defined implicitly in a marker trait (a trait that does not provide any function-ality) or explicitly through method signatures. Each type that wishes to implement a traitmust implement that trait’s declared interface. Traits also include associated items, includ-ing associated types—type-level functions similar to associated types in Haskell [12]—andthey provide the ability to create trait objects. Trait-based overloads are normally resolvedstatically, so successful overload resolution is guaranteed at compile-time, which also enablesthe language implementers to avoid introducing runtime overhead through the use of traits.However, trait objects also allow dynamic dispatch of overloads and they provide a heteroge-neous view on values implementing the same trait, regardless of those values’ concrete types.All in all, traits are a powerful part of Rust’s type system: they inform the design of closures(anonymous functions that enclose their surrounding environment), they are the mechanismthat enables operator overloading and they form an integral part of Rust’s safety story.The main contribution of this thesis is a formalization of Rust’s trait system. Specifically,we develop MiniRust: a formal model of a small subset of Rust’s type system including traits.For compactness, we do not model the type system features related to memory safety but weinclude more advanced features of the trait ecosystem such as supertraits, associated typesand trait objects, which allows us to gain insights into how those features interact with oneanother. To demonstrate the runtime semantics of programs with traits, we also developan internal language, RustIn, which doesn’t have traits. We present operational semanticsfor RustIn, we show how MiniRust programs can be translated to RustIn and we prove thatwell-typed MiniRust programs are type-safe. Finally, we adapt the Rust trait coherence rules,meant to prevent ambiguity of trait resolution in the presence of library dependencies. Weprove that the rules are sufficient to satisfy the desired guarantees, which in turn brings usa step closer to ensuring full type system coherence—that a program will behave the sameway regardless of the way it was typed.The rest of this thesis is organized as follows: in the next chapter we provide a moredetailed introduction to traits and how are they used in Rust, including the features thatare part of the formalization. Then, in chapter 3 we delve into the formalization, startingwith NanoRust: a formal model of a subset of the Rust type system including traits but omit-ting some of their more advanced features. We then present MicroRust in chapter 4, which3introduces associated types to NanoRust and finally MiniRust in chapter 5, which adds dy-namically sized types and trait objects. In chapter 6 we present RustIn, the internal languagefor MiniRust. The presentation includes the language’s type system, operational semanticsand a proof of type safety. Chapter 7 ties MiniRust and RustIn together by presenting type-directed translation rules from MiniRust to RustIn along with a proof that the translationpreserves well-typedness of programs. Then, in chapter 8 we discuss the notion of trait co-herence along with a proof of certain properties of the coherence rules. Finally, in chapter 9we discuss limitations of our work and possible extensions to the formalization, in chapter10 we present related work, and in chapter 11 we conclude the thesis.4Chapter 2Traits in RustThis chapter presents an introduction to traits in Rust. Most of the material in this chapteris adapted from the official Rust book [7], where we refer the reader for more details.2.1 FunctionsWe first present some basics of the Rust language that are relevant to our formalization.A Rust program consists of a collection of items. Among others, items may include func-tion declarations, datatype declarations, traits and impls. We first introduce function decla-rations.Below is a simple Rust program:fn square(x: f64) -> f64 {x * x}fn main() {let y = 1.2;let y_squared = square(y);println!("The square of {} is {}.", y, y_squared);}The program computes the square of 1.2 and prints it to standard output. At the topof the program is a declaration of the function square. Function declarations are explicitlytyped in Rust: the types of a function’s arguments and return value must be provided by theprogrammer. The function signature fn square(x: f64) -> f64 contains the name of thefunction, the name and type of its argument x: f64 and the function’s return type on theright side of the arrow (-> f64). f64 is one of the primitive types in Rust—it ranges over64-bit floating point numbers. Other primitive types include signed and unsigned integers of5different sizes (i8, u16, etc.), characters char, booleans bool and the unit type (), which isassociated with the unit expression (). The body of square is just a single expression. Thereturn value of the function is the result of evaluating that expression, which in this case isthe square of x.The starting point of a Rust program is the main function. Its function signature is equiv-alent to fn main() -> (), since the last statement in the function’s body can be consideredas an expression that returns the unit value (the absence of a return type in the functionsignature is syntactic sugar for -> ()).The let keyword is used to declare new local variables. Local variable declarations donot require explicit type annotations in most cases, as long as the compiler has enough infor-mation to infer their types.2.2 Structs and pointersRust also allows creating user-defined datatypes. For instance, a struct is a composite datatype with named fields. A struct declaration declares the name of a struct along with its fieldsand their respective types:struct Point {x: i32,y: i32}fn get_x(p: &Point) -> i32 {p.x}fn main() {let my_point = Point { x: 4, y: 6 };let my_x = get_x(&my_point);assert_eq!(my_x, 4);}In the above program, we first define a new struct Point, which consists of two 32-bitinteger fields x and y. Having defined the struct, we can use Point as a type. In the functionsignature of get_x, the type annotation &Point signals that the argument p is a reference (thebasic kind of pointer in Rust) to a Point. In the function’s body, the dot operator in p.x isused to access the field x of p. The dot operator also automatically dereferences the receiveras necessary. Therefore, since p is a pointer to a Point, p.x is equivalent to (*p).x, wherethe * operator first dereferences p before its x field is accessed.6In the main function in the example above we create a new instance of Point and weassign it to the local variable my_point. We then pass a reference to my_point (denoted bythe reference operator &) to get_x and we use the assert_eq! macro to assert that the call toget_x returns the expected result of 4 (the symbol ! denotes macros in Rust).2.3 TraitsIn its simplest form, a trait is a collection of method interfaces parameterized by an implicitSelf type variable. An impl contains implementations of all of the trait’s methods for somespecific type instantiation of Self.struct Point {x: i32,y: i32}trait Eq {fn eq(&self, &Self) -> bool;}impl Eq for Point {fn eq(&self, other: &Point) -> bool {self.x == other.x && self.y == other.y}}In the above example, we define the trait Eq 1, whose body consists of the type signature ofmethod eq, which checks for equality between two values of type Self (note that the methodreceives pointers to those values and not the values themselves). Since eq is a method, thefirst argument in its type signature, &self, stands for the receiver of the method and it hastype &Self (self is a special keyword used for the method receiver of type Self). Then, wehave an impl of Eq for our new type Point, where we must provide an implementation ofeq, with all instances of the type variable Self replaced with Point (&self in the functionsignature is equivalent to self: &Point).The trait declaration allows us to call eq with values of any type that implements Eq,which includes Point:let (p1, p2) = (Point {x: 3, y: 4}, Point {x: 4, y: 5});let are_equal = p1.eq(&p2);1Our Eq trait is a simplified version of the equivalence relation traits in the standard library, which are usedto overload the == operator: https://doc.rust-lang.org/stable/std/cmp/7The dot operator in the above example is used to call the method eq on the receiver p1.When using the method call notation, the receiver is automatically referenced when needed,so the last line is equivalent tolet are_equal = (&p1).eq(&p2);Note that the call to eq is dispatched statically: the concrete implementation of eq usedin the above call is determined at compile-time.We can also constrain type parameters of generic functions by traits:fn triple_equal<T>(first: &T, second: &T, third: &T) -> boolwhere T: Eq {first.eq(second) && second.eq(third)}In the first line of the function signature of triple_equal we learn that the function is genericover type variable T. The where-clause on the second line contains a constraint T: Eq, whichmeans “T implements Eq” and restricts the types allowed to instantiate T to only those thatimplement Eq. In consequence, we are able to use this additional information about T in thebody of the function. Concretely, we gain access to the functionality provided by Eq and wecan call the trait’s eq method on a reference to a value of type T.Impls themselves can also be generic and constrained as in the following example:struct Pair<T> {first: T,second: T}impl<T> Eq for Pair<T> where T: Eq {fn equals(&self, other: &Pair<T>) -> bool {self.first.equals(other.first) &&self.second.equals(other.second)}}In the above example, Pair is a generic struct used to create pairs of values of any type (aslong as the type is the same for both values). The corresponding impl is generic over the typeT of the values in the pair. The where-clause restricts T to be instantiable only with a typethat implements Eq. The constraint in the where-clause is then available to the functions inthe impl’s body.2.4 Associated functions & UFCSIn Rust, the body of a trait may also include associated functions, which do not require self(or a pointer to self) to appear as the first argument in their type signature. In consequence,8associated functions cannot be invoked using method syntax. A call to an associated functionmust be prefixed by the name of the trait, using the so-called universal function call syntax(UFCS). For example, the Rust standard library contains a trait Default, used for types thathave a default value:trait Default {fn default() -> Self;}The type signature of default does not include self as its first argument. Thus, default isan associated function and it can only be called using UFCS. The concrete type, whose implof Default we would like to use, can appear in the function call prefix:let x = <i32 as Default>::default();or it can be omitted as long as the surrounding context contains enough type information:let y: i32 = Default::default();Trait methods can also be called using UFCS. The receiver of the method is then simplypassed as the first argument to the function call.2.5 SupertraitsTraits in Rust allow a form of interface inheritance through supertraits:trait Ord: Eq {fn lt(&self, &Self) -> bool;fn le(&self, &Self) -> bool;}impl Ord for Point {fn lt(&self, other: &Point) -> bool {self.x < other.x ||(self.x == other.x && self.y < other.y)}fn le(&self, other: &Point) -> bool {self.lt(other) || self.eq(other)}}In the above example, the header of the Ord trait declaration contains a bound : Eq,which asserts that Eq is a supertrait of Ord (the trait header is equivalent to trait Ord whereSelf: Eq). The supertrait constraint acts as an obligation for impls of Ord: only types thatalready implement Eq can implement Ord (the obligation is enforced by the compiler). At the9same time, the constraint acts as a guarantee to users of Ord (generic functions constrainedby Ord) that any type that implements Ord also implements Eq. The functionality provided byEq then becomes available for values of any type implementing Ord. This allows us to writefunctions like the following:fn eq_and_le<T>(first: &T, second: &T, third: &T) -> boolwhere T: Ord {first.eq(second) && first.le(third)}where we call eq (a method of the trait Eq) on first, even though the where-clause in thefunction signature does not explicitly contain the constraint T: Eq.2.6 Multi-parameter traits & associated typesSo far we have only seen single-parameter traits, parameterized by the implicit Self typevariable. Traits, however, can have an arbitrary number of additional type parameters. Wecan, for example, define the trait WeightedGraph using multiple type parameters:trait WeightedGraph<N, E> where E: HasWeight {fn edges(&self) -> &Vec<E>;...}WeightedGraph is parameterized by Self, corresponding to the graph itself, and by type vari-ables N and E, corresponding to the node and edge types respectively.We can then use the trait in a generic function as in the example below:fn graph_size<G, N, E>(graph: &G) -> usizewhere G: WeightedGraph<N, E> {graph.edges().len()}where we must also explicitly parameterize the function by the node and edge types.However, if the concrete instantiations of N and E are always uniquely determined by theconcrete type instantiation of G, we can declare the types of nodes and edges as associatedtypes instead:10struct MyNode { ... }struct MyWeightedEdge { ... }trait WeightedGraph2 {type Node;type Edge: HasWeight;fn edges(&self) -> &Vec<Self::Edge>;}impl WeightedGraph2 for MyGraph {type Node = MyNode;type Edge = MyWeightedEdge;fn edges(&self) -> &Vec<MyWeightedEdge> {...}}fn graph_size<G>(graph: &G) -> u32 where G: WeightedGraph2 {graph.edges().len()}An associated type acts as a named output parameter of a trait. Only Self and the otherinput parameters declared in the trait header are used to determine the specific impl used toresolve a call to an overloaded method or function. The concrete associated type instantiationis uniquely determined by those parameters (assuming no overlap in impl declarations). Anassociated type can thus be interpreted as a type-level function: its arguments are the nameof the trait and its input parameters, and its return value is the associated type’s instantia-tion provided in the impl.We declare a new associated type in the body of a trait declaration using the type key-word. For example, in the code above, the trait WeightedGraph2 declares two associatedtypes: Node and Edge. An impl must also “implement” all associated types defined in itsimplemented trait by providing their instantiations. To use an associated type of a trait,we specify the name of the trait along with its type parameters, e.g. we use the syntax<T as WeightedGraph2>::Node to denote the associated type Node instantiated in the impl ofWeightedGraph2 for type T. In the case where there is no ambiguity as to which trait is beingreferenced, Rust lets us omit the trait name, e.g. T::Node.Associated types defined in trait declarations can also be constrained. For example, theassociated type Edge in WeightedGraph2 is bounded by the HasWeight trait. Like super-trait bounds, associated type bounds serve as obligations for all impls of a trait to makesure that the types that instantiate the associated type satisfy the constraints. Those con-straints are propagated similarly to supertrait constraints, meaning that a satisfied trait11constraint is sufficient to automatically infer that the constraints on that trait’s associatedtypes (and the trait’s supertrait constraints) are satisfied as well. Therefore, the constraintEdge: HasWeight is available to users of WeightedGraph2:trait HasWeight {fn weight(&self) -> u32;}fn weighted_graph_size<G>(graph: &G) -> u32 where G: WeightedGraph2 {graph.edges().iter().fold(0u32, |acc: u32, item: &G::Edge| acc + item.weight())}In the body of weighted_graph_size we use fold: a method of the Iterator trait. Themethod performs the reduce or combine operation on the elements of the iterator that ispassed to it as the receiver. The arguments to fold are the initial value of the accumulator(0u32 in this case) and a function that specifies the combine operation. In the above example,the combine operation is specified by the closure (an anonymous function)|acc: u32, item: &G::Edge| acc + item.weight(). The closure takes two arguments:an accumulator acc and an edge item (the type annotations in the example are not actu-ally necessary as they can be inferred by the compiler), and returns the result of evaluatingacc + item.weight(). We know that item’s type, &<G as WeightedGraph2>::Edge, is a ref-erence to an associated type of the trait WeightedGraph2. Meanwhile, the method weight()belongs to the trait HasWeight, and so can only be called on a reference to a value whosetype implements HasWeight. We can, however, call the method weight() on item withoutexplicitly including the constraint <G as WeightedGraph2>::Edge: HasWeight in the where-clause of the function because the constraint Edge: HasWeight in the trait declaration ofWeightedGraph2 is propagated.Finally, the programmer can write generic functions constrained by associated types. Forexample, the Iterator trait in the Rust standard library 2 has an associated type that corre-sponds to the type of the values of the iterator:trait Iterator {type Item;...}If we want to write a function that can be used with any iterator of 32-bit integers, we cansimply specify the requirement in the where-clause by extending the trait constraint with anassociated type equality:2https://doc.rust-lang.org/std/iter/trait.Iterator.html12fn iterate<T>(iterator: &T) where T: Iterator<Item=i32> { ... }2.7 Trait objectsAbstraction without overhead is an important design principle in Rust: abstractions in thelanguage should not incur any performance penalties. To avoid generating run-time overheadfrom the use of generics and traits, the Rust compiler monomorphizes its generic functionsand methods. The process consists of turning each generic function into multiple monomor-phic functions: one for each instantiation of the function’s type variables that occurs in theprogram. In addition to avoiding indirection and overhead caused by handling generics, theprocess allows the compiler to apply the function inlining optimization, which can make theresulting code more efficient. This way of translating generics can however lead to code bloat,which can result in large binaries. As an alternative to monomorphization, Rust provides theability to dispatch trait methods dynamically through trait objects.In Rust’s type system, a trait declaration creates a related type of the same name. Sucha type, which we call a trait type, describes values whose concrete types implement the trait(i.e., the concrete types are the Self parameters of the trait). The trait type is effectively anexistential type [28]: the concrete type of its value is existentially quantified—hidden fromthe type system’s field of view.In Rust’s memory model, where program values are allocated directly on the stack, thetype of a value informs the compiler of the value’s size and alignment requirements. However,in the case of a trait type, since the concrete type of the value is unknown, the size andalignment of the value are not known either, as a trait type may classify values of varyingsizes. The trait type is thus an instance of a dynamically sized type (DST)—a type whosevalues do not have a statically known size. As such, DST values must appear behind somekind of pointer.3A trait object is thus an object that contains a pointer to some value whose concrete typeimplements the trait, as well as a pointer to a vtable that contains pointers to the concretetrait methods that may be invoked on the object. The notation for the type of a trait objectlooks like a pointer to a trait type. For example, a trait object of the trait HasWeight can havetype &HasWeight (in Rust documentation, the implementation of a trait object is referred toas a fat pointer).To illustrate how trait objects work in Rust, consider the following example:3Another instance of a DST is the type of an unknown size array of 32-bit integers [i32]. The type &[i32]denotes a slice, which is an object that contains a pointer to the array as well as metadata including the array’slength.13struct Ball {radius: f64,weight: f64}struct Cube {width: f64,weight: f64}trait HasWeight {fn weight(&self) -> f64;}impl HasWeight for Ball {fn weight(&self) -> f64 { self.weight }}impl HasWeight for Cube {fn weight(&self) -> f64 { self.weight }}fn obj_weight(obj: &HasWeight) -> f64 { obj.weight() }The function obj_weight does not have to be monomorphized at compile-time because itis already monomorphic. The concrete implementation of the weight method that is used inthe body of obj_weight is the one referenced in the trait object obj’s vtable.To create a trait object we can explicitly cast a reference to a value whose type implementsthe trait (as its Self type) to a trait object:let ball = Ball { radius: 6.2, weight: 2.7 };let ball_object = &ball as &HasWeight;let ball_weight = obj_weight(ball_object);We can also implicitly coerce a reference to an object by passing it to a piece of code thatexpects a trait object:let ball = Ball { radius: 6.2, weight: 2.7 };let ball_weight = obj_weight(&ball);The ‘existential type’ nature of trait objects also allows us to have a heterogeneous viewof values that have different types but share a common trait. This is particularly useful increating collections of such values:14let ball = Ball { radius: 6.2, weight: 2.7 };let cube = Cube { width: 2.5, weight: 9.9 };let object_vector: Vec<&HasWeight> = vec!(&ball, &cube);for item in object_vector {println!("I weigh {} kg.", item.weight());}Since all trait objects of HasWeight have the same type, we can create a vector of all objectsof HasWeight, regardless of their concrete underlying types.To conclude discussion of trait objects, we must note that not all traits can be used tocreate an object—only traits that are deemed object-safe can be used to do so. Roughly speak-ing, a trait is object-safe if all of its methods are object-safe. A method is object-safe if it isnot generic and if in its type signature Self only appears behind a pointer as the receiverof the method (the restriction is necessary to prevent runtime type errors in operations ontrait objects). However, the requirements for object safety get more complex in the presenceof supertraits and associated types. We discuss those requirements in more detail when weintroduce trait objects to MiniRust in chapter 5.15Chapter 3NanoRust: a language with traitsIn this chapter we begin the formal development of a subset of Rust with a focus on traits.Our goal is to have the formal model include some of the more advanced features of thetrait system, namely associated types and trait objects. However, in an attempt to keep thepresentation accessible to the reader, we defer including those features until later chapters.Therefore, in this chapter we introduce NanoRust: a simple language with traits but withoutassociated types and trait objects, both of which will be introduced in subsequent chapters aspart of MicroRust and MiniRust respectively.3.1 Some syntactic conventionsWe first set up some syntactic conventions, which we use throughout the remainder of thisthesis.We use the overline, e.g. τ, to denote sequences of zero or more elements. We use low-ercase subscripts to distinguish between different sequences. For example, τi and τ j rep-resent different sequences. We reuse the same subscript to denote sequences of the samelength: τi has the same length as Ti. If an overline is extended over both subscripted andnon-subscripted items, the non-subscripted items remain constant. For example, Γ`WF τirepresents repetition of Γ `WF τ for each τ ∈ τi. In the case where we want to specify that asequence forms an unordered set, we use curly braces: {τi}.In type schemes of the form ∀T.pi⇒ τ, we can omit the for-all quantifier ∀ if the sequenceof type variables T is empty. Similarly, we can remove the qualification symbol ⇒ if thesequence of constraints pi is empty as well. Therefore, assuming that () denotes an emptysequence, we consider ∀().()⇒ τ equivalent to τ. The same convention applies to constraintschemes ∀T.pi⇒pi.We use [τ/T] to denote a substitution. For instance, [τ/T]pi represents the result of sub-stituting all free occurrences of the type variable T in pi with the type τ.16e ∈ TERM, T,Self ∈ TVAR, S ∈ SCONS, τ ∈ TYPEx, f ∈VAR, D ∈ TRAIT, σ ∈ TSCHEME, θ ∈CSCHEMEpgm ::= item (programs)item ::= struct S 〈T〉 {x : τ} (items)| fun| trait D 〈T〉 for Self where pi { f :σ }| impl〈T〉D 〈τ〉 for τwhere pi { fun }fun ::= fn f 〈T〉 (x : τ)→ τwhere pi { e } (functions)e ::= let x= e in e | lv := e | e; e |&lv | ∗e (terms)| e(e) | x | () | e as τ | S{x : e} | e.xlv ::= x | ∗e | lv.x (lvalues)τ ::= () | T | fn(τ)→ τ |&τ | S 〈τ〉 (types)σ ::= ∀T.pi⇒ τ (type schemes)θ ::= ∀T.pi⇒pi (constraint schemes)pi ::= τ :β (trait constraints)β ::= D 〈τ〉 (trait bounds)Γ ::= ; |Γ, x :σ |Γ,T |Γ,S 〈T〉 {x : τ} (typing environments)| Γ, (D 〈T〉where pi,Self :β, f )Θ ::= ; |Θ,θ (constraint environments)Figure 3.1: NanoRust: syntax3.2 SyntaxFigure 3.1 presents the syntax of NanoRust. The syntax gives us a glimpse of the featuresof Rust modeled in this thesis. Note that, to keep our formalization relatively lightweight,we only model a small subset of the language. As a general rule, we include features thatare relevant to traits and some features that—we believe—capture the essence of Rust. Forinstance, imperative features, such as references and assignment expressions, demonstratethe systems language nature of Rust. References also form an integral part of our formaliza-tion of trait objects in chapter 5. We also include structs, which let us create new types. Weuse structs in the translation of MiniRust to its internal language in chapter 7. We notablyomit the features of Rust’s type system that focus on memory safety. For instance, lifetimesplay a significant role in Rust’s trait system, however they are omitted from the model due tothe complexity that they bring to the language. We do believe, however, that they would bean interesting addition to the formalization, worth exploring in future work.3.2.1 ItemsPrograms in NanoRust consist of a collection of items. The items we model in NanoRustinclude struct declarations, functions, traits, and impls.17A struct declaration defines a new composite data type along with its structure: the namesof its fields and their respective types. Struct declarations may also be polymorphic. A dec-laration struct S 〈T j〉 {xi : τi} defines the polymorphic type ∀T j.S 〈T j〉. We can interpret thepolymorphic type as a family of types S 〈τ j〉. The types τi of the struct fields xi are thenparametric over the instantiations τ j of T j.Every function declaration is explicitly typed and, like structs, can be polymorphic. Inthe function signature fn f 〈T j〉 (xi : τi) → τ where pik, f is the name of the function, T j arethe type variables over which the function is parameterized, xi : τi are the names and typesof the function arguments, and τ is the return type. The where-clause where pik containsconstraints on the function’s type parameters, which must be satisfied by any instantiationof the function. The return value of the function is the result of evaluating its body e, whichis a single expression. We require programs to have a function fMAIN, corresponding to Rust’smain function, which serves as the starting point of a NanoRust program.A trait declaration consists of two parts: the header and the body. The headertrait D 〈Ti〉 for Self where pi j declares the name of the trait D, the name of its Self parame-ter Self and non-Self parameters Ti (note that in contrast to Rust, trait headers in NanoRustexplicitly declare the Self type variable in anticipation of kinds in chapter 5). The where-clause where pi j contains supertrait constraints Self : β and any other constraints τ : β thatmust be satisfied by every impl that implements the trait.In Rust, the body of a trait may include both trait methods, where self (or a referenceto it) appears as the first argument in the method signature and acts as a receiver, andassociated functions, which do not have the restriction on self but in consequence can onlybe called using UFCS, described in the previous chapter. To keep the syntax of terms inNanoRust as concise as possible, we do not support method call syntax. This lets us unifytrait methods and associated functions in the form of trait functions. To call a trait function,we use standard function syntax (without a trait name prefix), following the lead of classmethods in Haskell [40]. To avoid ambiguities related to multiple traits declaring functionsof the same name, we simply require that all functions in a program, including trait functions,have unique names.The body of a trait declaration in NanoRust consists of a single trait function. Specifically,it contains the function’s name and its type signature in the form of a type scheme. Therestriction on the number of functions in a given trait is purely motivated by the clarity ofpresentation of the model. It should be fairly straightforward to add support for an arbitrarynumber of trait functions; we believe that doing so, however, would increase the complexityof the formal model without shedding new conceptual light on the language.An impl declaration provides an implementation of a trait. The impl headerimpl〈T j〉D 〈τi〉 for τwhere pik provides an instantiation of the trait parameters for which the18implementation is written: τ is an instantiation of Self and τi are instantiations of the non-Self trait parameters. The impl, along with its type instantiations, is parameterized by typevariables T j, which are constrained by constraints pik in the where-clause. The body of theimpl provides a concrete implementation of the trait function.Rust also allows declaring nested items, which effectively restricts where such items arevisible. However, semantics of nested items are the same as the semantics of top-level items.In particular, an inner function nested inside an outer function does not capture the localvariables from the outer function in its scope (Rust does provide however the ability to writeclosures—anonymous functions that enclose their surrounding environment, which are notpart of this formalization). For simplicity, in NanoRust we only permit items declared at thetop level of the program.3.2.2 Termse ranges over terms (or expressions) in NanoRust. Terms include:• let x= e1 in e2: a local variable declaration equivalent to let x = e; e in Rust,• lv := e: an assignment expression (equivalent to lv = e in Rust), which assigns theresult of evaluating the expression e to the location represented by the lvalue lv 1,• e; e: which permits chaining expressions and can be used to emulate statements, sincethe result of evaluating the first term is discarded,• &lv: the reference operation, which returns a reference to the value stored at the mem-ory location represented by the lvalue lv (all references in NanoRust are mutable),• ∗e: the dereference operation, which returns the value stored at the memory locationrepresented by e,• e(e): a function call,• x: an identifier ranging over term variable names (local variables, functions, etc.),• (): the unit expression associated with no computation,• S{x : e}: a struct instance,• e.x: a struct field access expression and1 Local variables are immutable by default in Rust. However, since the NanoRust type system does not keeptrack of mutability of individual variables and we want to have a notion of mutable state in the model, localvariables in NanoRust are always mutable.19• e as τ: a type ascription. Type ascriptions in Rust are used to cast the type of a termto another type. In NanoRust, they are used to simulate programmer-supplied typeannotations since the syntax does not include explicitly annotated let-expressions (e.g.let x: i32 = 4; can be written as let x = 4 as i32 in . . . ), or explicitly parameter-ized struct instantiations and function calls (e.g. <i32>::print(4) can be written as(print as fn (i32)→ ())(4)).The metavariable lv ranges over lvalues: terms that represent memory locations. As such,they can be assigned to and they can be referenced. They include identifiers x, dereferenceoperations ∗x and field accesses lv.x.3.2.3 TypesEvery term that occurs in a NanoRust program has a type represented by the metavariableτ. Types include:• unit type (): the type of the unit expression (),• type variable T, which we can interpret as a type placeholder, used to depict generics,• function type fn(τi)→ τ, which ranges over functions that take arguments of types τiand return a value of type τ,• reference type &τ, and• struct type S 〈τi〉: type of instances of struct S whose type parameters are instantiatedto types τi.We omit primitive machine types such as integers and booleans. We believe that their in-clusion would not bring any useful insight into the semantics of the NanoRust. Adding prim-itive types with their corresponding terms and operations should however be fairly straight-forward.3.2.4 Polymorphic typesThe types we have seen so far are monomorphic: they correspond to a single ‘concrete’ typerepresentation. In order to reason about generic language constructs, we also include thenotion of a polymorphic type (a type that may take on multiple concrete representations)through type schemes. In a system without traits (or similar constructs) and constraints, atype scheme σ is generally of the form ∀Ti.τ. We can understand it to mean that a valuethat is assigned a type scheme σ can have type [τi/Ti]τ for any choice of types τi. This formof type scheme is sufficient to support parametric polymorphism, which is expressed in Rustthrough generics.20To enable ad-hoc polymorphism through traits, we need to be able to constrain the typevariables occurring in a type scheme. Thus, type schemes in NanoRust are qualified: theyinclude predicates (which we also call constraints) that must be satisfied before the typescheme’s type variables can be instantiated. A qualified type scheme [20] has form ∀Ti.pi j ⇒ τ.The type scheme is qualified by constraints (or predicates) pi j. As such, a value with a typescheme ∀Ti.pi j ⇒ τ can have type [τi/Ti]τ for any choice of types τi such that the predi-cates [τi/Ti]pi j are satisfied. In NanoRust, those predicates are trait constraints of the formτ : D 〈τk〉, which we read as “type τ implements trait D with parameters τk”. From this pointon, we simply refer to qualified type schemes as type schemes.To express generic constraints, we also include constraint schemes, which also can bequalified. Similar to type schemes, they have form form ∀Ti.pi j ⇒ pi which we can read as:“for any type instantiation τi of types Ti such that the predicates [τi/Ti]pi j are all satisfied,[τi/Ti]pi is satisfied as well”. In a constraint scheme ∀Ti.pi j ⇒ pi, we refer to pi j as the quali-fying constraints, and we refer to pi as the principal constraint of the constraint scheme.3.2.5 EnvironmentsIn order to type expressions, we carry two environments containing our current assumptionsabout what is in scope. The typing environment Γ is a set that contains variable typings x :σ,type variables that are in scope, available struct definitions, and tuples that contain informa-tion about traits that have been declared. A trait information tuple (D 〈T〉where pi,Self : β, f )is implicitly quantified by the type variables Self and T. It consists of the trait headerD 〈T〉where pi, supertrait bounds Self :β, and an identifier f corresponding to the name of thetrait function. We also have a constraint environment Θ that is a set of constraint schemescorresponding to impls that we can assume to be in scope.3.2.6 ExampleTo show how a Rust program may be represented in NanoRust, consider the following exam-ple from chapter 2:21struct Point {x: i32,y: i32}trait Eq {fn eq(&self, &Self) -> bool;}impl Eq for Point {fn eq(&self, other: &Point) -> bool {self.x == other.x && self.y == other.y}}fn main() {let (p1, p2) = (Point {x: 3, y: 4}, Point {x: 4, y: 5});let are_equal = p1.eq(&p2)}An equivalent representation of the above program in NanoRust would look as follows:struct Point{ x : i32, y : i32 }trait Eq for Self { eq : fn(&Self, &Self)→ bool }impl Eq for Point{fn eq(self :&Point, other :&Point)→ bool {&&(==((∗self).x, (∗other).x), ==((∗self).y, (∗other).y))}}fn main()→ () {let p1= Point{x : 3, y : 4} inlet p2= Point{x : 4, y : 5} inlet are_equal= eq(&p1, &p2) in ()}where && and == are some two-argument functions in scope. Note that NanoRust does notinclude automatic referencing and dereferencing—such operations must be made explicit.3.3 Well-formedness and constraint entailmentFigure 3.2 contains the well-formedness and constraint entailment judgments.At the top of the figure we have an auxiliary relation Γ ` τ : D 〈τi〉, which ensures thatthe trait D is in scope and is provided the right number of parameters. The single rule of the22(D 〈Ti〉where _,_,_) ∈ΓΓ` τ : D 〈τi〉Γ`WF σ (Well-formed type schemes)(wf-var)T ∈ΓΓ`WF T(wf-unit)Γ`WF ()(wf-fun)Γ`WF τi Γ`WF τΓ`WF fn(τi)→ τ(wf-ref)Γ`WF τΓ`WF &τ(wf-struct)(S 〈Ti〉 {x j : τ j}) ∈Γ Γ`WF τiΓ`WF S 〈τi〉(wf-tscheme)Γ,Ti `WF pi jjΓ,Ti `WF τΓ`WF ∀Ti.pi j ⇒ τΓ`WF θ (Well-formed constraint schemes)(wf-cscheme)Γ,Ti `WF pi j Γ,Ti `WF piΓ`WF ∀Ti.pi j ⇒pi(wf-trcons)Γ` τ : D 〈τi〉 Γ`WF τ Γ`WF τiΓ`WF τ : D 〈τi〉Γ |Θpi (Constraint entailment)(c-entail)(∀Ti.pi j ⇒pi) ∈Θ Γ`WF τi Γ |Θ [τi/Ti]pi jΓ |Θ [τi/Ti]piFigure 3.2: NanoRust: well-formedness and constraint entailmentrelation uses the trait tuple in the typing environment Γ to obtain the relevant information.Note that the tuple is implicitly quantified by the type variables Ti. Throughout this thesiswe maintain a convention that bound variables can be renamed, so the choice of names of thevariables Ti does not matter (e.g. (D 〈T1〉 ,Self, f ) is equivalent to (D 〈T2〉 ,Self, f )).The well-formed type schemes judgment Γ `WF σ can be interpreted as: “type schemeσ is well-formed with respect to Γ”. Intuitively, a type or type scheme is well-formed if itcan plausibly be assigned to some expression or item under the current set of assumptions.Specifically, the well-formedness judgment ensures that the type variables (in rule (wf-tvar))and structs (in rule (wf-struct)) used in the type are in the current set of assumptions in Γ.In rule (wf-tscheme), the type variables over which the type scheme is universally quantifiedare added into the set of assumptions in the premises, which verify well-formedness of thetype scheme’s components. This enables the body of the type scheme to mention those type23variables.The judgment is principally used to verify that type annotations provided by the pro-grammer “make sense”. Strictly speaking, the well-formedness checks are not necessary toensure type safety in NanoRust. However, a term with an ill-formed type will not be veryuseful as the typing rules prevent it from being used in any practical manner. Checking forwell-formedness can however help weed out ill-formed type annotations in item declarationsand thus reduce the amount of dead code in well-typed programs. It also allows us to rea-son about well-formed environments, which will be important when we discuss the dynamicsemantics of our language and trait coherence in chapters 7 and 8.The well-formed constraint schemes judgment Γ `WF θ verifies well formedness of con-straints and constraint schemes. In particular, the rule (wf-trcons) verifies that a trait con-straint refers to a trait that has actually been declared in the program and that the numberof type parameters in the constraint matches the trait declaration.The constraint entailment judgment Γ | Θ pi verifies that the constraint pi is satisfiedunder the set of constraint assumptions Θ and typing environment Γ. The judgment consistsof a single rule (c-entail), which looks up the relevant constraint scheme in the constraintenvironment Θ and verifies that the qualifying predicates pi j are satisfied, under the appro-priate instantiation of the type variables Ti, over which the constraint scheme is quantified.Note that due to our syntactic convention that lets us remove unneeded quantifiers ∀ andqualifiers ⇒, the rulepi ∈ΘΓ |Θ`piis just a special case of (c-entail).3.4 Well-typed termsFigure 3.3 presents the typing rules for terms in NanoRust. The typing judgmentΓ | Θ ` e : τ can be read as: “term e has type τ under sets of assumptions Γ and Θ”. Onething to note about this judgment is that, while the variable bindings in Γ may be assignedpolymorphic types (or type schemes), the typing judgment assigns a monomorphic type τ toeach term. This is due to the fact that the use of generics in Rust is limited: only top-levelitems may declare new polymorphic constructs and all type parameters of a generic itemhave to be instantiated with some monomorphic types before the item can be used.The rule (var), used for typing term variables, reflects this principle. If the variable isbound to a type scheme in Γ, then the type variables Ti in the type scheme must be instan-tiated to some types τi. If the type scheme is also qualified, we must also check that theconstraints [τi/Ti]pi j are satisfied.Note that the rule does not tell us which specific types τi to use for the type variable24Γ |Θ` e : τ (Well-typed terms)(as)Γ |Θ` e : τΓ |Θ` e as τ : τ (unit) Γ |Θ` () : () (let-un)Γ |Θ` e1 : τ1Γ, x : τ1 |Θ` e2 : τ2Γ |Θ` let x= e1 in e2 : τ2(seq)Γ |Θ` e1 : τ1 Γ |Θ` e2 : τ2Γ |Θ` e1; e2 : τ2(var)(x :∀Ti.pi j ⇒ τ) ∈ΓΓ`WF τi Γ |Θ [τi/Ti]pi jjΓ |Θ` x : [τi/Ti]τ(app)Γ |Θ` e : fn(τi)→ τΓ |Θ` e i : τiΓ |Θ` e(e i) : τ(ref)Γ |Θ` lv : τΓ |Θ`&lv :&τ (deref)Γ |Θ` e :&τΓ |Θ`∗e : τ(asgn)Γ |Θ` lv : τΓ |Θ` e : τΓ |Θ` lv := e : () (new-struct)S 〈Tk〉 {xi : τi} ∈ΓΓ |Θ` e i : [τk/Tk]τi Γ`WF τkΓ |Θ` S{xi : e i} : S 〈τk〉(proj)Γ |Θ` e : S 〈τ j〉 S 〈T j〉 {xm : τm, x : τ, xn : τn} ∈ΓΓ |Θ` e.x : [τ j/T j]τFigure 3.3: NanoRust: well-typed termsinstantiations. NanoRust’s type system can thus allow multiple typings of the same program.An implementation of the type system would have to perform some type inference in order tochoose type instantiations appropriate in the given context.Finally, note that our syntactic conventions make the rule(x : τ) ∈ΓΓ` x : τa special case of an application of (var).3.5 Well-typed items & programsFigure 3.4 presents the typing rules for items and programs.The purpose of the well-typed items judgment is to populate the top-level typing andconstraint environments with relevant assumptions obtained from program items. The judg-ment ΓI |ΘI ` item : ΓO |ΘO takes as input environments ΓI ,ΘI and it produces output envi-ronments ΓO,ΘO. In the well-typed programs judgment `P pgm :Γ |Θ we see that the outputenvironments of each item are in fact subsets of the input environments. As such, the input25Γ |Θ` item :Γ |Θ (Well-typed items)(struct)Γ,T j `WF τiiΓ |Θ` struct S 〈T j〉 {xi : τi} : [S 〈T j〉 {xi : τi}] | ;(fun)σ=∀Tk.pi j ⇒ fn(τi)→ τ Γ`WF σ Γ,Tk, xi : τi |Θ,pi j ` e : τΓ |Θ` fn f 〈Tk〉 (xi : τi)→ τwhere pi j { e } : [ f :σ] | ;(trait){pi j}≡ {Self :βs,pih} Tp = Self,Ti Γ`WF ∀Tp.(Self : D 〈Ti〉)⇒pi jjσ=∀Tk.pil ⇒ fn(τm)→ τR σ′ =∀Tp.(Self : D 〈Ti〉)⇒σ Γ`WF σ′Γ |Θ` trait D 〈Ti〉 for Selfwhere pi j { f :σ }:[(D 〈Ti〉where pih, Self :βs, f ), ( f :σ′)] |[∀Tp.(Self : D 〈Ti〉)⇒ Self :βss](impl)(D 〈Ti〉where pih, Self :βs, f ) ∈Γ τp = τ,τi Tp = Self,Ti Tk ∈ FV (τp)Γ |Θ`WF ∀Tk.pi j ⇒ τ : D 〈τi〉 Θ∗ =Θ\{∀Tp.(Self : D 〈Ti〉)⇒ Self :βss}Γ,Tk |Θ∗,pi j [τp/Tp](Self :βs)sΓ,Tk |Θ∗,pi j [τp/Tp]pihh( f :∀Tp.(Self : D 〈Ti〉)⇒σ) ∈Γ Γ,Tk |Θ∗,pi j ` fun : [ f :σ′] | ; σ′ = [τp/Tp]σΓ |Θ` impl〈Tk〉D 〈τi〉 for τwhere pi j {fun }: ; | [∀Tk.pi j ⇒ τ : D 〈τi〉]`P pgm :Γ |Θ (Well-typed programs)(pgm)Γ |Θ` itemi :Γi |Θi Γ=Γi Θ=Θi`P itemi :Γ |ΘFigure 3.4: NanoRust: well-typed items and programsenvironments to program items are unions of the output environments of each item (we usethe notation Γi as syntactic sugar for⋃{Γi}). This allows us to declare mutually dependentitems, such as mutually recursive functions.The typing rule for structs is straightforward: it checks that the types of the struct fieldsare well-formed and it adds the struct definition to the typing environment. The typingrule for functions, (fun), generates a type scheme σ from the function signature and it usesthe well-typed terms judgment to ensure that the body of the function is well-typed whileextending the sets of assumptions with the type parameters of the function, the functionarguments, and the constraints pi j from the function’s where-clause.263.5.1 Well-typed traitsThe typing rule for traits, (trait), produces three results:• a tuple that represents the obligations that impls of the trait must fulfill,• a binding of the trait function name to its type signature, and• propagated constraint schemes corresponding to the trait’s supertraits, which implythat, given a satisfied trait constraint, its corresponding supertrait constraints are alsosatisfied.Supertrait constraints are part of the trait declaration’s where-clause. As of version 1.3of the compiler, Rust restricts supertrait constraints to be of the form Self :β. In consequence,any additional constraints in the where-clause (in the form of bounds on a non-Self type) arenot propagated: the user of the trait is not able to assume that non-supertrait constraintsfrom the where-clause are satisfied. For example, given the following traits:struct Wrapper<T> { ... }trait Copy {fn copy(self) -> Self;}trait Wrappable where Wrapper<Self>: Copy {fn wrap(self) -> Wrapper<Self>;}the following function would not type-check:fn wrap_and_copy<T>(arg: T) -> Wrapper<T> where T: Wrappable {arg.wrap().copy()}For wrap_and_copy to be well-typed, the constraint Wrapper<T>: Copy has to be explicitlyincluded in its where-clause. The restriction seems to be a side effect of the history of devel-opment of traits and where-clauses in Rust as supertrait constraints (in the form of boundson Self) predate where-clauses.In NanoRust, we inherit the same restriction on supertraits and we do not propagate non-supertrait constraints. In the first side condition of the rule, {pi j}≡ {Self :βs,pih}, we separatesupertrait constraints Self :βs from the other constraints. We then verify that the constraintsin the where-clause are well-formed.To verify well-formedness of the programmer-provided trait function type signature σ,we first build a generalized type scheme σ′. To do so, we quantify σ by the trait param-eters and we qualify the resulting type scheme with the trait constraint. We then verify27that σ′ is well-formed. Note that the notation ∀Tp.(Self : D 〈Ti〉) ⇒ σ is syntactic sugar for∀Tp,Tk.(Self : D 〈Ti〉 ,pil)⇒ τ where σ=∀Tk.pil ⇒ τ.3.5.2 Well-typed implsThe rule (impl) ensures that the impl declaration fulfills the obligations set out by the traitthat it is implementing and it adds the appropriate constraint scheme to the set of assumedconstraints. The impl itself can be universally quantified by type variables Tk and con-strained by predicates pi j in the impl’s where-clause.In the side condition Tk ∈ FV (τp), we use a function FV that returns the set of free typevariables in a given type or sequence of types. The side condition ensures that the typevariables, over which the impl is quantified are all part of the impl’s trait parameter instan-tiations.When verifying entailment of constraints in the implemented trait’s where-clause andwhen typing the trait function implementation, we use a modified constraint environmentΘ∗, which omits the propagated supertrait constraint schemes of the implemented trait fromΘ. Doing so prevents trivial entailment of the supertrait constraints: since the output con-straint scheme of the impl is also part of the input constraint environment Θ, we could useit in conjunction with the supertrait constraint scheme from the trait typing rule to concludethat the supertrait constraint is satisfied. For example, consider the following program:trait Bar { ... }trait Foo: Bar { ... }impl Foo for i32 { ... }The top-level constraint environment Θ generated for the program would be{∀Self.Self : Foo⇒ Self : Bar, i32 : Foo}.We would then be able to obtain a derivation of Γ |Θ i32 : Bar and falsely assume that thesupertrait constraint is satisfied.28Chapter 4MicroRust: NanoRust withassociated typesIn this chapter we extend NanoRust with associated types and equality constraints, creatinga new language, which we call MicroRust. Our formal treatment of associated types andtype equality constraints presented in this chapter is largely inspired by work on Haskellassociated type synonyms [12].4.1 SyntaxFigure 4.1 contains the syntax of MicroRust. The highlighted parts represent new additionsto the language.4.1.1 Associated typesThe bodies of trait and impl declarations in MicroRust include associated types. As with traitfunctions, we require each trait to have exactly one associated type. It should however befairly straightforward to add support for an arbitrary number of associated types in a trait.A trait declaration declares an associated type constructor A in its body using the syntaxtype A : β, where β are bounds on the associated type. In an impl, the associated type A isinstantiated to some type τ using the declaration type A 7→ τ. The impl must also ensure thatτ satisfies the bounds β on A that occur in the trait declaration.The syntax of types is extended with an associated type AD 〈τ,τi〉, where, in addition tothe associated type constructor A, we include the name of the trait D that A is associatedwith, the trait’s Self parameter τ and the additional trait parameters τi. In particular, anassociated type AFoo 〈T1,T2,T3〉 is equivalent to <T1 as Foo<T2, T3>>::A in Rust. All ofthe components of the associated type application are necessary to ensure that the type ismatched to the appropriate trait and impl in the general case—to simplify our type system,we do not allow omitting the trait name or the trait parameters, even if they could, in princi-29e ∈ TERM, T,Self ∈ TVAR, S ∈ SCONS, τ ∈ TYPEA ∈ACONS, x, f ∈VAR, D ∈ TRAIT, σ ∈ TSCHEME, θ ∈CSCHEMEpgm ::= item (programs)item ::= struct S 〈T〉 {x : τ} (items)| fun| trait D 〈T〉 for Self where pi { type A :β; f :σ }| impl〈T〉D 〈τ〉 for τwhere pi { type A 7→ τ; fun }fun ::= fn f 〈T〉 (x : τ)→ τwhere pi {e} (functions)e ::= let x= e in e | lv := e | e; e |&lv | ∗e (terms)| e(e) | x | () | e as τ | S{x : e} | e.xlv ::= x | ∗e | lv.x (lvalues)τ ::= () | T | fn(τ)→ τ |&τ | S 〈τ〉 | AD 〈τ,τ〉 (types)σ ::= ∀T.pi⇒ τ (type schemes)θ ::= ∀T.pi⇒pi (constraint schemes)pi ::= τ :β (trait constraints)β ::= D 〈τ, A 7→ τ 〉 |D 〈τ, A 7→? 〉 (trait bounds)Γ ::= ; |Γ, x :σ |Γ,T |Γ,S 〈T〉 {x : τ} (typing environments)| Γ, (D 〈T〉where pi,Self :β, A :β, f )Θ ::= ; |Θ,θ (constraint environments)Figure 4.1: MicroRust: syntaxple, be inferred.Note that the syntax does not prevent impl declarations from instantiating an associatedtype with another associated type. This is also allowed by our typing rules, however, toprevent circularity in associated type instantiations, we externally require that each concreteassociated type (without unsolved type variables) can be normalized, i.e., converted to anequivalent concrete type expression without associated types. For instance, in an impl oftrait D1, it is possible to have an associated type instantiation type A 7→ AD2 〈bool〉 as longas AD2 〈bool〉 normalizes to some concrete type (such as i32 for example).4.1.2 Type equality constraintsWith the addition of associated types to the language we also need a notion of type equalityor equivalence of type expressions. For example, given an implimpl Foo for i32 { type A 7→ bool; }30we want to be able to conclude that the type expression AFoo 〈i32〉 is equivalent to bool. Toreflect this idea, we introduce type equality constraints of the form τ1 ∼ τ2, which we use toconvert between equivalent type expressions (such as in the type of a term).We also extend the syntax of trait bounds to allow parameterizing trait constraints bytheir associated type: the extended trait constraint τ : D 〈τi, A 7→ τA〉 tells us that type τ im-plements trait D with additional type parameters τi, and the corresponding associated typeAD 〈τ,τi〉 is instantiated with the type expression τA. A MicroRust trait bound D 〈T1, A 7→T2〉is equivalent to the bound D<T1, A=T2> in Rust.1 The extended trait constraint lets us con-strain functions by an associated type as in the following function that is parametric overiterators of 32-bit integers:fn iterate<T>(iterator: T) where T: Iterator<Item=i32> { ... }Rust does not require trait constraints to include their associated type instantiations.To account for such cases, where the associated type instantiation is not known and/or notneeded, we include constraints of the form τ : D 〈τi, A 7→?〉 where ? denotes an identity as-sociated type instantiation—an instantiaton of an associated type with itself. In the typingrules we will often use the notation τ : D 〈τi〉 as syntactic sugar for τ : D 〈τi, A 7→?〉.4.2 Typing rules4.2.1 Well-formedness judgmentsThe well-formedness judgments in MicroRust are presented in figure 4.2. At the top of thefigure we define a new auxiliary relation Γ ` AD , which verifies that the associated typeconstructor A is associated with trait D.In a departure from NanoRust, the well-formedness judgments include the constraintenvironment Θ. The environment is needed in the new rule (wf-atype) of the well-formedtypes judgment, which verifies that an associated type AD 〈τ,τi〉 is well-formed. All associ-ated types are related to a trait constraint and an associated type only has meaning if itscorresponding trait constraint is satisfied. As such, the rule (wf-type) invokes the constraintentailment judgment to verify that its corresponding constraint τ : D 〈τi, A 7→?〉 is entailed.Note that the dependence on the constraint entailment relation in the rule effectively makesthe well-formed types and constraint entailment judgments mutually dependent on one an-other.Rule (wf-tscheme), used to verify well-formedness of type schemes, extends the constraintenvironment in its premises with the qualifying constraints of the type scheme. Doing so1 A trait constraint in Rust may also include instantiations of associated types of supertraits of the constraint’strait. We do not allow this in our model, however it is a feature we would consider in future work.31(D 〈Ti〉where _,_,_,_) ∈ΓΓ` τ : D 〈τi〉(D 〈_〉where _,_, A : _,_) ∈ΓΓ` ADΓ |Θ`WF τ (Well-formed types)(wf-var)T ∈ΓΓ |Θ`WF T(wf-unit)Γ |Θ`WF ()(wf-fun)Γ |Θ`WF τi Γ |Θ`WF τΓ |Θ`WF fn(τi)→ τ(wf-ref)Γ |Θ`WF τΓ |Θ`WF &τ(wf-struct)(S 〈Ti〉 {x j : τ j}) ∈Γ Γ |Θ`WF τiΓ |Θ`WF S 〈τi〉(wf-atype)Γ |Θ τ : D 〈τi, A 7→?〉 Γ |Θ`WF τ Γ |Θ`WF τiΓ |Θ`WF AD 〈τ,τi〉Γ |Θ`WF σ (Well-formed type schemes)(wf-tscheme)Γ,Ti |Θ,pi j `WF pi jjΓ,Ti |Θ,pi j `WF τΓ |Θ`WF ∀Ti.pi j ⇒ τΓ |Θ`WF θ (Well-formed constraint schemes)(wf-cscheme)Γ,Ti |Θ,pi j `WF pi jjΓ,Ti |Θ,pi j `WF piΓ |Θ`WF ∀Ti.pi j ⇒pi(wf-treqcons)Γ` τ : D 〈τi〉 Γ` AD Γ |Θ`WF τ Γ |Θ`WF τi Γ |Θ`WF τAΓ |Θ`WF τ : D 〈τi, A 7→ τA 〉(wf-trcons)Γ` τ : D 〈τi〉 Γ` AD Γ |Θ`WF τ Γ |Θ`WF τiΓ |Θ`WF τ : D 〈τi, A 7→? 〉Figure 4.2: MicroRust: well-formedness judgments32allows us to have type schemes that include associated types that are associated with traitsby which the type scheme is constrained. For example, in the type scheme∀T.(T : Foo, AFoo 〈T〉 : Bar)⇒ τthe associated type AFoo 〈T〉 is well-formed because the trait constraint T : Foo is addedto the set of impl assumptions in rule (wf-tscheme) and it is in the scope of the rule in-stance of (wf-atype) that verifies well-formedness of AFoo 〈T〉. The rule (wf-cscheme), usedto verify well-formedness of constraint schemes, extends Θ similarly in its premises. Rules(wf-treqcons) and (wf-trcons) verify well-formedness of constraints. If a constraint is of theform τ : D 〈τi, A 7→ τA〉 then we also verify that the associated type instantiation τA is well-formed.4.2.2 Constraint entailmentFigure 4.3 presents rules used to prove constraint satisfaction. The rules are part of twomutually inductive judgments: the trait constraint entailment judgment Γ | Θ pi and theequality constraint entailment judgment Γ |Θ τ∼ τ.The trait constraint entailment judgment contains new rules (c-treq1) and (c-treq2), whichprove entailment of a trait constraint, whose type parameters and associated type instantia-tion (if present) are equivalent to some type expressions, for which the constraint is satisfied.The rule (c-astar) also lets us infer entailment of a trait constraint with an identity asso-ciated type instantiation (A 7→ ?) from a corresponding satisfied trait constraint with anyassociated type instantiation τA.The equality constraint entailment judgment Γ |Θ τ1 ∼ τ2 asserts that type expressionτ1 is equivalent to τ2 under assumptions in Γ and Θ. Rule (eq-sep) infers a type equalityfrom an associated type instantiation A 7→ τA in a trait constraint. Rules (eq-refl), (eq-trans)and (eq-sym) respectively reflect the reflexivity, transitivity and symmetry properties of thetype equality relation. The remaining rules in the judgment are used to prove equivalence ofinductively defined type expressions.4.2.3 Well-typed termsFigure 4.4 presents the well-typed terms judgment in MicroRust. The only addition to thejudgment is the rule (sub), which allows converting the type expression of a term e to anotherequivalent type expression. Note that, unlike other rules in the well-typed terms judgment,rule (sub) does not depend on the structure of the term e and thus it can be used at any pointin a typing derivation. It would be up to an implementation or a corresponding type inferencealgorithm to decide when to convert the type of a term.33Γ |Θpi (Trait constraint entailment)(c-ext)(∀Ti.pi j ⇒pi) ∈Θ Γ |Θ`WF τi Γ |Θ [τi/Ti]pi jΓ |Θ [τi/Ti]pi(c-treq1)Γ |Θ τ1 : D 〈τ1 i, A 7→ τ3〉 Γ |Θ τ1 ∼ τ2 Γ |Θ τ1 i ∼ τ2 iiΓ |Θ τ3 ∼ τ4Γ |Θ τ2 : D 〈τ2 i, A 7→ τ4〉(c-treq2)Γ |Θ τ1 : D 〈τ1 i, A 7→?〉Γ |Θ τ1 ∼ τ2 Γ |Θ τ1 i ∼ τ2 iiΓ |Θ τ2 : D 〈τ2 i, A 7→?〉(c-astar)Γ |Θ τ : D 〈τi, A 7→ τA〉Γ |Θ τ : D 〈τi, A 7→?〉Γ |Θ τ∼ τ (Equality constraint entailment)(eq-sep)Γ |Θ τ : D 〈τi, A 7→ τA〉Γ |Θ AD 〈τ,τi〉 ∼ τA(eq-refl)Γ |Θ τ∼ τ (eq-trans)Γ |Θ τ1 ∼ τ3Γ |Θ τ3 ∼ τ2Γ |Θ τ1 ∼ τ2(eq-sym)Γ |Θ τ2 ∼ τ1Γ |Θ τ1 ∼ τ2(eq-struct)Γ |Θ τ1 i ∼ τ2 iiΓ |Θ S 〈τ1 i〉 ∼ S 〈τ2 i〉(eq-ref)Γ |Θ τ1 ∼ τ2Γ |Θ&τ1 ∼&τ2(eq-fun)Γ |Θ τ1 i ∼ τ2 iiΓ |Θ τ1 ∼ τ2Γ |Θ fn(τ1 i)→ τ1 ∼ fn(τ2 i)→ τ2(eq-atype)Γ |Θ τ1 ∼ τ2 Γ |Θ τ1 i ∼ τ2 iΓ |Θ AD 〈τ1,τ1 i〉 ∼ AD 〈τ2,τ2 i〉Figure 4.3: MicroRust: constraint entailment4.2.4 Well-typed itemsIn the well-typed items judgment in figure 4.5, rules (trait) and (impl) contain additionsnecessary to accommodate the inclusion of associated types (those additions are highlightedin the figure).In the trait typing rule, (trait), the bounds on the associated type A : βa are propagatedmuch like supertrait bounds and thus are treated similarly. The trait information tupleoutput by the rule also includes the name of the trait’s associated type constructor and itsbounds.The impl typing rule, (impl), verifies that the associated type instantiation provided in34Γ |Θ` e : τ (Well-typed terms)(sub)Γ |Θ` e : τ1 Γ |Θ τ1 ∼ τ2Γ |Θ` e : τ2(as)Γ |Θ` e : τΓ |Θ` e as τ : τ (unit) Γ |Θ` () : ()(let-un)Γ |Θ` e1 : τ1 Γ, x : τ1 |Θ` e2 : τ2Γ |Θ` let x= e1 in e2 : τ2(seq)Γ |Θ` e1 : τ1Γ |Θ` e2 : τ2Γ |Θ` e1; e2 : τ2(var)(x :∀Ti.pi j ⇒ τ) ∈ΓΓ |Θ`WF τi Γ |Θ [τi/Ti]pi jjΓ |Θ` x : [τi/Ti]τ(app)Γ |Θ` e : fn(τi)→ τΓ |Θ` e i : τiΓ |Θ` e(e i) : τ(ref)Γ |Θ` lv : τΓ |Θ`&lv :&τ (deref)Γ |Θ` e :&τΓ |Θ`∗e : τ (asgn)Γ |Θ` lv : τΓ |Θ` e : τΓ |Θ` lv := e : ()(new-struct)S 〈Tk〉 {xi : τi} ∈ΓΓ |Θ` e i : [τk/Tk]τi Γ |Θ`WF τkΓ |Θ` S{xi : e i} : S 〈τk〉(proj)Γ |Θ` e : S 〈τ j〉S 〈T j〉 {xm : τm, x : τ, xn : τn} ∈ΓΓ |Θ` e.x : [τ j/T j]τFigure 4.4: MicroRust: well-typed termsthe body of an impl satisfies the bounds on the associated type specified in the implementedtrait declaration. To prevent trivial resolution of those constraints through use of the propa-gated associated type constraint schemes produced by the trait typing rule, we use a trimmedconstraint environment Θ∗, where the propagated associated type constraint schemes (alongwith supertrait constraint schemes) are omitted. Finally, the rule produces a trait constraintthat contains the associated type instantiation defined in the impl.35Γ |Θ` item :Γ |Θ (Well-typed items)(struct)Γ,T j |Θ`WF τiiΓ |Θ` struct S 〈T j〉 {xi : τi} : [S 〈T j〉 {xi : τi}] | ;(fun)σ=∀Tk.pi j ⇒ fn(τi)→ τ Γ |Θ`WF σΓ′ =Γ,Tk, xi : τi Θ′ =Θ,pi j Γ′ |Θ′ ` e : τΓ |Θ` fn f 〈Tk〉 (xi : τi)→ τwhere pi j { e } : [ f :σ] | ;(trait){pi j}≡ {(Self :βs),pih} Tp = Self,Ti Γ |Θ`WF ∀Tp.(Self : D 〈Ti〉)⇒pi jjσ=∀Tk.pil ⇒ fn(τm)→ τR σ′ =∀Tp.(Self : D 〈Ti〉)⇒σΓ |Θ`WF σ′ Γ |Θ`WF ∀Tp.(Self : D 〈Ti〉)⇒ AD 〈Tp〉 :βaaΓ |Θ`trait D 〈Ti〉 for Selfwhere pi j {type A :βa;f :σ; }:[(D 〈Ti〉where pih, Self :βs, A :βa, f ), f :σ′] |[∀Tp.(Self : D 〈Ti〉)⇒ Self :βss,∀Tp.(Self : D 〈Ti〉)⇒ AD 〈Tp〉 :βaa](impl)(D 〈Ti〉where pih, Self :βs, A :βa, f ) ∈Γ τp = τ,τi Tp = Self,TiTk ∈ FV (τp) Γ |Θ`WF ∀Tk.pi j ⇒ τ : D 〈τi〉Θ∗ =Θ\{∀Tp.(Self : D 〈Ti〉)⇒ Self :βss, ∀Tp.(Self : D 〈Ti〉)⇒ AD 〈Tp〉 :βaa}Γ,Tk |Θ∗,pi j [τp/Tp](Self :βs)sΓ,Tk |Θ∗,pi j [τp/Tp]pihhΓ,Tk |Θ∗,pi j `WF τA Γ,Tk |Θ∗,pi j τA : [τp/Tp]βaa( f :∀Tp.(Self : D 〈Ti〉)⇒σ) ∈Γ Γ,Tk |Θ∗,pi j ` fun : [ f :σ′] | ; σ′ = [τp/Tp]σΓ |Θ` impl〈Tk〉D 〈τi〉 for τwhere pi j {type A 7→ τA; fun } : ; | [∀Tk.pi j ⇒ τ : D 〈τi, A 7→ τA 〉]`P pgm :Γ |Θ (Well-typed programs)(pgm)Γ |Θ` itemi :Γi |Θi Γ=Γi Θ=Θi`P itemi :Γ |ΘFigure 4.5: MicroRust: well-typed items and programs36Chapter 5MiniRust: MicroRust with traitobjectsIn this chapter we present MiniRust: an extension of MicroRust where we include trait ob-jects: trait-based existential objects that introduce dynamic dispatch to the language.5.1 SyntaxFigure 5.1 presents the syntax of MiniRust.5.1.1 Trait objectsA trait object is an existential object that encapsulates the functionality provided by its trait.The Self type of the object’s trait is existentially quantified (hidden from the type system’sfield of view) [28]. The type of a trait object, &(∃T : D 〈u j, AD i 〈T,u〉 ∼ ui〉), is composed ofthe reference operator & and the trait object descriptor ∃T : D 〈u j, AD i 〈T,u〉 ∼ ui〉. The useof the reference operator & follows from the trait object often being called a fat pointer inRust. However, a trait object is not really a pointer—it is really an object that containsadditional information about its encapsulated value—thus we consider the reference typeoperator & as overloaded in MiniRust. The trait object descriptor (or just descriptor for short)looks like a trait constraint. This is intended to emphasize that the existentially quantifiedtype T implements the trait D. Since only Self is existentially quantified, the additionalparameters of the trait appear in the trait object type as u j (u ranges over types in MiniRust).Finally, since associated type instantiations are determined by the trait parameters, they arealso specified in the type of the trait object as AD i 〈T,u〉 ∼ ui. They include not only typesassociated with the trait of the descriptor, but also associated types of all supertraits in thetrait’s supertrait hierarchy (in Rust, an object’s supertrait associated types must also beexplicitly declared in the object’s type). This allows us, for example, to call trait functionsthat return a value whose type is an associated type of a supertrait of the object’s trait—the37e ∈ TERM, Self, X ∈XVAR, SelfT,T ∈ TVAR, SelfU,U ∈UVAR, S ∈ SCONS,τ ∈ STYPE , u ∈ TYPE , AT ∈ TACONS, AU ∈UACONS, A ∈ACONS, x, f ∈VAR,D ∈ TRAIT, σ ∈ TSCHEME, θ ∈CSCHEME, obj ∈ {obj-safe,obj-unsafe}pgm ::= item (programs)item ::= struct S 〈X 〉 {x : τ} (items)| fun| trait D 〈X 〉 for Selfwhere pi { type A :β, f :σ }| impl〈X 〉D 〈u〉 for uwhere pi { type A 7→ u, fun }fun ::= fn f 〈X 〉 (x : τ)→ τwhere pi {e} (functions)e ::= let x= e in e | lv := e | e; e |&lv | ∗e (terms)| e(e) | x | () | e as τ | S{x : e} | e.xlv ::= x | ∗e | lv.x (lvalues)τ ::= () | T | fn(τ)→ τ |&u | S 〈u〉 | ATD 〈u,u〉 (s-types)u ::= τ | U | ∃T : D 〈u, AD 〈T,u〉 ∼ u〉 | AUD 〈u,u〉 (types)X ::= T | U (type variables)Self ::= SelfT | SelfU (self type variables)A ::= AT | AU (associated type constructors)σ ::= ∀X .pi⇒ τ (type schemes)θ ::= ∀X .pi⇒pi (constraint schemes)pi ::= u :β (constraints)β ::= D 〈u, AT 7→ τ〉 | D 〈u, AU 7→ u〉 |D 〈u, A 7→?〉 (trait bounds)Γ ::= ; |Γ, x :σ |Γ, X |Γ,S 〈X 〉 {x : τ} (typing environments)| Γ, (D 〈X 〉where pi,Self :β, A :β, f , obj )Θ ::= ; |Θ,θ (constraint environments)Figure 5.1: MiniRust: syntaxtype equality in the type of the trait object can be used to convert the associated type to itsconcrete representation. Note that two trait objects of the same trait must have the sameassociated type instantiations to have the same type.The syntax of the descriptor in MiniRust differs from its equivalent representation inRust in that we explicitly introduce a type variable T that represents the hidden Self type.For example, given a trait Graph that has two associated types Node and Edge, its trait objectin Rust has type &Graph<Node=MyNode, Edge=MyEdge>. Its equivalent MiniRust represen-tation is &(∃T : Graph〈NodeTGraph 〈T〉 ∼ MyNode, EdgeTGraph 〈T〉 ∼ MyEdge〉). While this notationis heavier, it makes certain typing rules simpler, since they don’t need to rely on the typingenvironment to know the exact type parameters of a supertrait’s associated type.385.1.2 S-typesOne purpose of types in Rust is to assist the compilation process by providing the size ofprogram values, so that they can be properly allocated on the stack. In some cases, however,the type of a value does not provide that information. Such a type is said to be dynamicallysized. A notable instance of a dynamically sized type (DST) is the trait type: it describesvalues whose concrete types implement a given trait. Such values may have different sizes,however their type is ignorant of them. As such, a trait type, and a DST in general, may notbe assigned directly to a value.In MiniRust we introduce a similar distinction between directly storable s-types τ, whichmodel Rust’s statically sized types, and indirectly storable types u, which model possibly-dynamically sized types. An s-type classifies values that can be stored directly in memory(specifically, in the store, as we will see in chapter 6). The trait object descriptor, which modelsRust’s trait type, is part of the set of types but it is not an s-type. However, a ‘reference to adescriptor’—a trait object—is an s-type.To allow generic items to be parameterized by types and s-types, we distinguish betweentype and s-type variables: U and T respectively. In Rust, the distinction between dynamicallyand statically sized types is expressed as a bound on a type variable: T: Sized represents astatically sized type variable, while T: ?Sized represents a possibly-dynamically sized typevariable. In cases where the bound is omitted, a default is assumed (the default is usuallySized, except for the Self type of a trait, whose default bound is ?Sized).The syntactic approach to distinguishing between the two kinds of type variables inMiniRust is slightly more restrictive. In particular, Rust trait declarations may contain meth-ods that restrict Self to be Sized even if at the trait level, Self is ?Sized. In MiniRust thereis no direct way to restrict the sizedness of a trait parameter on a per-function basis (althoughit’s not really relevant, since each MiniRust trait only contains one function). However, byreducing the notational burden associated with sizedness bounds we obtain a more concisesyntax.For the cases where we do not know (or care about) the kind of a type variable—whetherit is a type or s-type variable—we include a metavariable X that ranges over both kinds ofvariables. Similarly, the special variable Self is now a metavariable that ranges over SelfTand SelfU, which represent an s-type and type variable respectively.Associated types can also be instantiated with trait object descriptors in MiniRust (inRust they can be instantiated with any DST). For that reason, similarly to type variables,we distinguish syntactically between associated type and s-type constructors as AU and ATrespectively. A is then a metavariable that ranges over both kinds of associated type con-structors. If an associated type represents an s-type (ATD 〈. . .〉), it can only be instantiatedwith an s-type. We define the following predicate, which we use in our typing rules to protect39(D 〈X i〉where _,Self : _,_,_,_) ∈Γ[u/Self][ui/X i] definedΓ` u : D 〈ui〉(D 〈_〉where _,_, A : _,_,_) ∈ΓΓ` AD(D 〈_〉where _,_,_,_,obj-safe) ∈ΓΓ`D obj-safeS 〈X i〉 {. . . } ∈Γ [ui/X i] definedΓ` S 〈ui〉Figure 5.2: MiniRust: auxiliary relationsthat requirement:[AT 7→ τ] defined [AU 7→ u] definedWith the distinction of type and s-type variables, we must also revisit our definition oftype substitution to prevent an s-type variable from being instantiated with a type that isnot an s-type (recall that all s-types are types). A substitution [u/X ] is only defined when thepredicate [u/X ] defined holds. The predicate is defined as follows:[u/U] defined [τ/T] definedFor example, a substitution [u/T] where u 6∈ STYPE is undefined.5.1.3 Object-safe traitsNot all traits can be used to create trait objects. Rust (and MiniRust) has a notion of objectsafety that restricts which traits can be used to create trait objects. If a trait satisfies theobject safety requirements then its resulting trait information tuple will reflect that in itslast field, being obj-safe. Otherwise, a trait that’s not object-safe will have obj-unsafe as thelast field of its information tuple. We discuss object safety in detail in section 5.3.5.2 Type system5.2.1 Auxiliary relationsFigure 5.2 presents auxiliary relations that extract information from trait information tuplesin the typing environment Γ. The relation Γ ` u : D 〈ui〉 is extended to verify that the traitparameter instantiations in the constraints u : D 〈ui〉 have kinds that are compatible withthe trait declaration.The relation Γ` AD asserts that the type constructor A is associated with trait D. Since40AD is a metavariable ranging over ATD and AUD , the relation informs us of the associatedtype’s kind.In the same figure we also find the relation Γ`D obj-safe, which asserts that a trait D isobject-safe. Finally, the relation Γ` S 〈ui〉 verifies that S is a struct in the typing environmentΓ, and that its type parameter instantiations ui have the right kinds.5.2.2 Well-formed typesFigure 5.3 presents the MiniRust well-formedness judgments. A major difference from thecorresponding judgments in MicroRust is that generic constructs are now parameterized byvariables X , which can be either type (U) or s-type (T) variables. In rules (wf-struct) and(wf-trcons) we use the auxiliary relations Γ ` S 〈u〉 and Γ ` u : D 〈u〉 respectively to ensurethat the type variables are instantiated with types of appropriate kind.As the language of types in MiniRust is extended with trait objects, the well-formed typesjudgment contains a new rule (wf-desc), used to verify that a trait object descriptor is well-formed. In its premise Γ,T |Θ,T : D 〈ui〉 `WF AD j 〈T,us j〉jwe add the existential type variableT and the constraint T : D 〈ui〉 to the sets of assumptions. Since supertrait constraints arepropagated, having a constraint T : D 〈ui〉 in the set of assumptions allows us to infer that thecorresponding supertrait constraints of the form T : D j 〈u〉 are satisfied, with an appropriatechoice of u. As the associated types on the left-hand side of the type equalities in the descrip-tor are associated with the descriptor’s trait and its supertraits, this enables us to prove theirwell-formedness, based on rule (wf-type). When verifying well-formedness of the right-handsides of the type equalities u j, we do not extend the sets of assumptions. By excluding T fromthe well-formed type judgment for u j, we specifically do not let T occur in u j in the interestof preserving type safety. If some type u ∈ u j is part of the return type of a trait function calland it contains T, then the existential variable T escapes its scope [28].5.2.3 Constraint entailmentThe constraint entailment judgments are presented in figure 5.4. The trait constraint entail-ment judgment is the same as in MicroRust, with the exception of using u instead of τ fortrait parameters. In rule (c-ext), instead of using the predicate [ui/X i] defined we directly ap-ply the substitution, as it’s only defined when the substitution’s components have compatiblekinds. The equality constraint entailment judgment includes a new rule, (eq-obj), that provesequivalence of two trait object descriptors by verifying that their respective components areequal.41Γ |Θ`WF u (Well-formed types)(wf-var)X ∈ΓΓ |Θ`WF X(wf-unit)Γ |Θ`WF ()(wf-fun)Γ |Θ`WF τi Γ |Θ`WF τΓ |Θ`WF fn(τi)→ τ(wf-ref)Γ |Θ`WF uΓ |Θ`WF &u(wf-struct)Γ` S 〈ui〉 Γ |Θ`WF uiΓ |Θ`WF S 〈ui〉(wf-atype)Γ |Θ u : D 〈ui, A 7→?〉 Γ |Θ`WF u Γ |Θ`WF uiΓ |Θ`WF AD 〈u,ui〉(wf-desc)Γ`D obj-safe Γ |Θ`WF ui Γ` SelfU : D 〈ui〉Γ,T |Θ,T : D 〈ui〉 `WF AD j 〈T,uk j〉jΓ |Θ`WF u jΓ |Θ`WF ∃T : D 〈ui, AD j 〈T,uk j〉 ∼ u j〉Γ |Θ`WF σ (Well-formed type schemes)(wf-tscheme)Γ, X i |Θ,pi j `WF pi jjΓ, X i |Θ,pi j `WF τΓ |Θ`WF ∀X i.pi j ⇒ τΓ |Θ`WF θ (Well-formed constraint schemes)(wf-cscheme)Γ, X i |Θ,pi j `WF pi j Γ, X i |Θ,pi j `WF piΓ |Θ`WF ∀X i.pi j ⇒pi(wf-treqcons)Γ` u : D 〈ui〉 Γ` AD Γ |Θ`WF u Γ |Θ`WF ui Γ |Θ`WF uAΓ |Θ`WF u : D 〈ui, A 7→ uA〉(wf-trcons)Γ` u : D 〈ui〉 Γ` AD Γ |Θ`WF u Γ |Θ`WF uiΓ |Θ`WF u : D 〈ui, A 7→?〉Figure 5.3: MiniRust: well-formedness judgments42Γ |Θpi (Trait constraint entailment)(c-ext)(∀X i.pi j ⇒pi) ∈Θ Γ |Θ`WF ui Γ |Θ [ui/X i]pi jΓ |Θ [ui/X i]pi(c-treq1)Γ |Θ u1 : D 〈u1 i, A 7→ u3〉 Γ` u2 : D 〈u2 i〉Γ |Θ u1 ∼ u2 Γ |Θ u1 i ∼ u2 iiΓ |Θ u3 ∼ u4Γ |Θ u2 : D 〈u2 i, A 7→ u4〉(c-treq2)Γ |Θ u1 : D 〈u1 i, A 7→ u3〉 Γ` u2 : D 〈u2 i〉 Γ |Θ u1 ∼ u2 Γ |Θ u1 i ∼ u2 iiΓ |Θ u2 : D 〈u2 i, A 7→?〉(c-astar)Γ |Θ u : D 〈ui, A 7→ uA〉Γ |Θ u : D 〈ui, A 7→?〉Γ |Θ u∼ u (Equality constraint entailment)(eq-sep)Γ |Θ u : D 〈ui, A 7→ uA〉Γ |Θ AD 〈u,ui〉 ∼ uA(eq-refl)Γ |Θ u∼ u (eq-trans)Γ |Θ u1 ∼ u3Γ |Θ u3 ∼ u2Γ |Θ u1 ∼ u2(eq-sym)Γ |Θ u2 ∼ u1Γ |Θ u1 ∼ u2(eq-struct)Γ` S 〈u1 i〉 Γ` S 〈u2 i〉 Γ |Θ u1 i ∼ u2 iiΓ |Θ S 〈u1 i〉 ∼ S 〈u2 i〉(eq-ref)Γ |Θ u1 ∼ u2Γ |Θ&u1 ∼&u2(eq-fun)Γ |Θ τ1 i ∼ τ2 iiΓ |Θ τ1 ∼ τ2Γ |Θ fn(τ1 i)→ τ1 ∼ fn(τ2 i)→ τ2(eq-atype)Γ` u1 : D 〈u1 i〉 Γ` u2 : D 〈u2 i〉 Γ |Θ u1 ∼ u2 Γ |Θ u1 i ∼ u2 iΓ |Θ AD 〈u1,u1 i〉 ∼ AD 〈u2,u2 i〉(eq-obj)Γ` SelfU : D 〈u1 i〉 Γ` SelfU : D 〈u2 i〉 Γ`T : D j 〈u1s j s〉jΓ`T : D j 〈u2s j s〉jΓ |Θ u1 i ∼ u2 i Γ,T |Θ,T : D 〈u1 i〉 u1s j ∼ u2s j Γ |Θ u1 j ∼ u2 jΓ |Θ ∃T : D 〈u1 i, AD j 〈T,u1s j〉 ∼ u1 j〉 ∼ ∃T : D 〈u2 i, AD j 〈T,u2s j〉 ∼ u2 j〉Figure 5.4: MiniRust: constraint entailment43Γ |Θ` e : τ (Well-typed terms)(sub)Γ |Θ` e : τ1 Γ |Θ τ1 ∼ τ2Γ |Θ` e : τ2(as)Γ |Θ` e : τΓ |Θ` e as τ : τ (unit) Γ |Θ` () : ()(let-un)Γ |Θ` e1 : τ1 Γ, x : τ1 |Θ` e2 : τ2Γ |Θ` let x= e1 in e2 : τ2(seq)Γ |Θ` e1 : τ1Γ |Θ` e2 : τ2Γ |Θ` e1; e2 : τ2(var)(x :∀X i.pi j ⇒ τ) ∈ΓΓ |Θ`WF ui Γ |Θ [ui/X i]pi jjΓ |Θ` x : [ui/X i]τ(app)Γ |Θ` e : fn(τi)→ τΓ |Θ` e i : τiΓ |Θ` e(e i) : τ(ref)Γ |Θ` lv : τΓ |Θ`&lv :&τ (deref)Γ |Θ` e :&τΓ |Θ`∗e : τ (asgn)Γ |Θ` lv : τΓ |Θ` e : τΓ |Θ` lv := e : ()(new-struct)S 〈Xk〉 {xi : τi} ∈ΓΓ |Θ` e i : [uk/Xk]τi Γ |Θ`WF ukΓ |Θ` S{xi : e i} : S 〈uk〉(proj)Γ |Θ` e : S 〈u j〉S 〈X j〉 {xm : τm, x : τ, xn : τn} ∈ΓΓ |Θ` e.x : [u j/X j]τ(obj-cast)Γ |Θ` e :&τ Γ |Θ τ : D 〈ui, A 7→?〉Γ |Θ [τ/T]u1 j ∼ u2 jjΓ |Θ (∃T : D 〈ui,u1 j ∼ u2 j〉) : D 〈ui, A 7→?〉Γ |Θ` e :&(∃T : D 〈ui,u1 j ∼ u2 j〉)Figure 5.5: MiniRust: well-typed terms5.2.4 Well-typed termsThe well-typed terms judgment, presented in figure 5.5, is extended with the rule(obj-cast) used to type coercions to a trait object. Note that the rule does not depend onthe structure of the term e. This allows us to coerce pointers to trait objects implicitly whenneeded, without using the as keyword.The purpose of the first premise Γ |Θ` e :&τ in the rule (obj-cast) is to obtain the type ofthe reference that is to be coerced to a trait object. The premise Γ |Θ τ : D 〈ui, A 7→?〉 ver-ifies that the referenced type τ, obtained in the preceding premise, implements the object’strait, along with the other type parameters specified. The premise Γ |Θ [τ/T]u1 j ∼ u2 jjen-sures that the type equalities in the trait object type are satisfied when instantiating theexistential type variable T with the concrete type τ. Finally, to ensure that the trait op-erations are available on the object, the premise Γ |Θ (∃T : D 〈ui,u1 j ∼ u2 j〉) : D 〈ui, A 7→?〉44verifies that the trait object descriptor implements its trait (we elaborate on this point insection 5.3).5.2.5 Well-typed itemsThe well-typed items judgment in figure 5.6 contains the same rules as the correspondingjudgment in MicroRust. The main difference between the judgments is that in MicroRust weuse variables X and types u as type parameters instead of s-type variables T and s-types τ,which allows us to parameterize items by types or s-types, as desired. Rule (trait) is usedto type non-object-safe traits. The trait information tuple in its output typing environmentcontains the flag obj-unsafe, which represents that the trait is not object-safe. Also, in rule(impl), we include the side condition [A 7→ uA] defined that ensures that the associated typeinstantiation in the impl has the correct kind. The judgment also has a new rule (obj-trt) fortyping object-safe traits, presented in figure 5.7. We discuss the new rule in detail in the nextsection.5.3 Object-safe traitsA trait object lets us reason about its encapsulated value in terms of the functionality pro-vided by its trait. In fact, since the concrete type of the value is hidden from the type system’sfield of view, the only operations allowed on a trait object are those defined by its trait (andits supertraits). To permit these operations on trait objects, the trait object descriptor effec-tively implements its trait—hence the premise Γ | Θ (∃T : D 〈ui,u1 j ∼ u2 j〉) : D 〈ui〉 in therule (obj-cast) in figure 5.5.However, some operations that may be defined in a trait are not feasible with a traitobject. For example, recall the trait Eq from chapter 2:trait Eq {fn eq(&self, &Self) -> bool;}Suppose that we have the following implementations:impl Eq for i32 { ... }impl Eq for char { ... }and a hypothetical impl for Eq’s trait type (using Rust syntax):impl Eq for Eq {fn eq(&self, &Eq) -> bool {// unpack objects and call the appropriate version of eq}}45Γ |Θ` item :Γ |Θ (Well-typed items)(struct)Γ, X j |Θ`WF τiiΓ |Θ` struct S 〈X j〉 {xi : τi} : [S 〈X j〉 {xi : τi}] | ;(fun)σ=∀Xk.pi j ⇒ fn(τi)→ τ Γ |Θ`WF σΓ′ =Γ, Xk, xi : τi Θ′ =Θ,pi j Γ′ |Θ′ ` e : τΓ |Θ` fn f 〈Xk〉 (xi : τi)→ τwhere pi j { e } : [ f :σ] | ;(trait){pi j}≡ {Self :βs,pih} X p =Self, X i Γ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒pi jjσ=∀Xk.pil ⇒ fn(τm)→ τR σ′ =∀X p.(Self : D 〈X i〉)⇒σΓ |Θ`WF σ′ Γ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βaaΓ |Θ`trait D 〈X i〉 for Selfwhere pi j {type A :βa;f :σ; }:[(D 〈X i〉where pih, Self :βs, A :βa, obj-unsafe), f :σ′] |[∀X p.(Self : D 〈X i〉)⇒Self :βss,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βaa](impl)(D 〈X i〉where pih, Self :βs, A :βa, f ,_) ∈Γ up = u,ui X p =Self, X iXk ∈ FV (up) Γ |Θ`WF ∀Xk.pi j ⇒ u : D 〈ui〉Θ∗ =Θ\{∀X p.(Self : D 〈X i〉)⇒Self :βss,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βaa}Γ, Xk |Θ∗,pi j [up/X p](Self :βs)sΓ, Xk |Θ∗,pi j [up/X p]pihh[A 7→ uA] defined Γ, Xk |Θ∗,pi j `WF uA Γ, Xk |Θ∗,pi j uA : [up/X p]βaa( f :∀X p.(Self : D 〈X i〉)⇒σ) ∈Γ Γ, Xk |Θ∗,pi j ` fun : [ f :σ′] | ; σ′ = [up/X p]σΓ |Θ` impl〈Xk〉D 〈ui〉 for uwhere pi j {type A 7→ uA; fun } : ; | [∀Xk.pi j ⇒ u : D 〈ui, A 7→ uA〉]... continued in figure 5.7`P pgm :Γ |Θ (Well-typed programs)(pgm)Γ |Θ` itemi :Γi |Θi Γ=Γi Θ=Θi`P itemi :Γ |ΘFigure 5.6: MiniRust: well-typed items and programs46Then, suppose that we call eq with a trait object:fn object_eq(obj: &Eq, other_obj: &Eq) -> bool {obj.eq(other)}If the concrete type behind obj is i32 and the one behind other_obj is char, then there is noappropriate concrete version of eq that we can call. 1To prevent such cases, Rust has a set of requirements for object-safe traits: traits that canbe used as bases to create trait objects. According to the documentation of the language [5], atrait is object-safe if its Self parameter is not marked as Sized and if each of its methods isobject-safe. A method is object-safe only if Self does not appear in the types of its argumentsand its return value. Also, an object-safe method may not be generic—a restriction due tomonomorphization that is part of Rust’s compilation model (we explore this in more detail inchapter 7). Moreover, since supertrait and associated type constraints are propagated, theallowed occurrences of Self inside them are restricted as well. However, the documentationdoes not currently address them and it is unclear what the rules are in that respect [5].The restrictions on the occurrences of Self must be relaxed somewhat when it comes toassociated types, since an associated type parameterized by Self may be instantiated witha concrete type that does not mention Self. In particular, since a trait object descriptorincludes instantiations of the associated types of the object’s trait and all of its supertraits,it appears reasonable to allow such associated types, parameterized by Self, to occur in thethe body of the trait.For instance, suppose that we have a trait Iterator implemented for a user-defined typeMyIterator (using Rust syntax):trait Iterator {type Item;fn next(&self) -> Self::Item;}impl Iterator for MyIterator {type Item = MyItem;fn next(&self) -> Self::Item { ... }}let my_iter: MyIterator = ...let iter_obj = &my_iter as &Iterator<Item=MyItem>;let my_item = my_iter.next();It is clear from the type of the trait object iter_obj that the call to my_item.next() returns avalue of type MyItem. As such, next() is considered object-safe and my_item has type MyItem.1In fact, this is an instance of the binary method problem [11].475.3.1 Typing object-safe traitsThe rule (obj-trt), used for typing object-safe traits, is presented in figure 5.7. Note that thetype system does not prevent an object-safe trait from being typed using rule (trait) instead.As long as the trait is not used to create trait objects in the program, using (trait) to type itsdeclaration will result in a valid typing.The main differences between (obj-trt) and (trait) are highlighted in the rule (obj-trt).One notable difference is that in (obj-trt), the Self variable is restricted to be a type variableSelfU. This restriction is necessary because we consider object-safe traits to be implementedfor their trait object descriptors, which are not s-types. Also, to mirror the restriction in Rustthat prevents declaring generic methods in an object-safe trait, we require the type of thetrait function f to be monomorphic.The primary results of the (obj-trt) rule for a trait D are the trait object constraint schemes∀X i, Xd.pid mm ⇒pidd. Each constraint pid corresponds to some trait Dd in D’s supertraithierarchy (including D itself) and it signals that uobj—the trait descriptor of D—implementsDd. Each constraint scheme is universally quantified by the non-Self type parameters of thetrait (X i), and the instantiations of the associated types of D and all of its supertraits (Xd).It is also qualified by the constraints pid m, representing Dd ’s supertrait and associated typeconstraints. Recall that, using rule (obj-cast), when we create an instance of a trait objectof D, we must prove that its descriptor implements its trait. To do that, we use the traitobject constraint scheme that corresponds to the descriptor’s trait D. In particular, when wecreate a trait object of D, we must ensure that the qualifying constraints in D’s trait objectconstraint scheme are satisfied, under appropriate instantiations of the constraint scheme’stype variables. Specifically, we verify that the associated type constraints are satisfied bythe concrete associated type instantiations declared in the descriptor and that the descriptoralso implements D’s supertraits (since the trait object constraint schemes output by (obj-trt)correspond to all traits in D’s supertrait hierarchy, we use them to prove that the descriptorimplements D’s supertraits).Building the trait object descriptorRecall that the descriptor of the trait D is of the form ∃T : D 〈ui, ADd 〈T,u〉 ∼ ud〉 where uiare the non-Self parameters of the described trait, ADd 〈T,u〉 are the associated types of Dand all its supertraits, and ud are their respective instantiations. In the rule (obj-trt) weuse the relation Γ ` D 〈ui〉 ⇑ {βs} to obtain all supertrait bounds in the supertrait hierarchyof the trait D (including the bound on D itself).2 From the resulting supertrait bounds wecan infer the associated types that are part of the trait descriptor uobj used in the output2Note that to obtain a derivation of Γ`D 〈ui〉 ⇑ {βs} for any ui and βs we must ensure that there are no cyclesin D’s supertrait relationship graph.48Γ |Θ` item :Γ |Θ (Well-typed items continued)(obj-trt){pi j}≡ {(SelfU :βs),pih} X p = SelfU, X i Γ |Θ`WF ∀X p.SelfU : D 〈X i〉⇒pi jjτ= fn(&SelfU,τm)→ τR σ′ =∀X p.(SelfU : D 〈X i〉)⇒ τΓ |Θ`WF σ′ Γ |Θ`WF ∀X p.(SelfU : D 〈X i〉)⇒ AD 〈X p〉 :βaaΓ`D 〈X i〉 ⇑{Dd 〈ud nn, Ad 7→?〉d}Ad :: Xduobj =∃T : D〈X i, ADd 〈T, [T/SelfU]ud nn〉 ∼ Xdd〉pid = uobj : Dd 〈[uobj/SelfU]ud nn, Ad 7→ Xd〉dθd =∀X i, Xd.piddΓ |Θ`WF θd Γ, X i, Xd |Θ | θd `os pid pid mmdΓ |Θ`trait D 〈X i〉 for SelfUwhere pi j {type A :βaf : τ }:[(D 〈X i〉where pih, SelfU :βs, A :βa, f ,obj-safe),f :σ′] |[∀X p.(SelfU : D 〈X i〉)⇒ SelfU :βss,∀X p.(SelfU : D 〈X i〉)⇒ AD 〈X p〉 :βaa,∀X i, Xd.pid mm ⇒pidd](D 〈X i〉 where _,SelfU : Ds 〈uns, As 7→ _〉, A : _,_,_) ∈Γ Γ`Ds 〈[ui/X i]uns〉 ⇑ {β j s}sΓ`D 〈ui〉 ⇑{β j s, D 〈ui, A 7→?〉}Γ |Θ1,Θ2 u1 ∼ u2 Γ |Θ1,Θ2 u1 i ∼ u2 i Γ |Θ1 `WF u2 : D 〈u2 i, A 7→?〉Γ |Θ1 |Θ2 ` u1 : D 〈u1 i, A 7→?〉V u2 : D 〈u2 i, A 7→?〉Γ |Θ1,Θ2 u1 ∼ u2 Γ |Θ1,Θ2 u1 i ∼ u2 iΓ |Θ1,Θ2 u3 ∼ u4 Γ |Θ1 `WF u2 : D 〈u2 i, A 7→ u4〉Γ |Θ1 |Θ2 ` u1 : D 〈u1 i, A 7→ u3〉V u2 : D 〈u2 i, A 7→ u4〉Γ |Θ | θd `os uobj : D 〈ui, A 7→ X 〉 pis,piawhereuobj =∃T : Dobj 〈Xh, ADd 〈T,und〉 ∼ Xd〉(D 〈X i〉 where _,SelfU :βs, A :βa, f ,obj-safe) ∈ΓΓ |Θ | θd ` uobj : [uobj/SelfU][ui/X i]βsVpissΓ |Θ | θd ` AD 〈uobj,ui〉 : [uobj/SelfU][ui/X i]βaVpiaa( f :∀SelfU, X i.(SelfU : D 〈X i〉)⇒ fn(&SelfU,τm)→ τR) ∈Γ(AD 〈T,u′i〉 ∼ X ) ∈ {ADd 〈T,und〉 ∼ Xd}Γ,T |Θ,θd,T : Dd 〈und, A ∼ Xd〉 [T/SelfU][u′i/X i]τR ∼ [uobj/SelfU][ui/X i]τRΓ,T |Θ,θd,T : Dd 〈und, A ∼ Xd〉 [uobj/SelfU][ui/X i]τm ∼ [T/SelfU][u′i/X i]τmmFigure 5.7: MiniRust: well-typed object-safe traits49trait object constraint schemes. We use type variables Xd to stand in for the associatedtype instantiations (they’re instantiated when a trait object instance is created). The sidecondition A :: X ensures that A and X have the same kind. We define the relation A :: X asfollows:AT :: T AU :: UFulfilling trait obligationsA nice advantage of having a trait object descriptor implement its trait is that we can writea generic function constrained by a trait and apply it not only to a concrete value that im-plements the trait but also to a trait object. For example, consider the following function (inRust syntax):fn area<T>(shape: &T) -> f64where T: ?Sized + HasArea { ... }Since T does not have to be a statically sized type, we can pass to area a reference to somevalue that implements the HasArea trait or a HasArea trait object.With this added flexibility, we must take additional care to ensure that each trait objectbehaves like a value that implements the object’s trait—specifically, it must support the sameoperations. To achieve that, we must make sure that if a trait object descriptor implementsa trait then it fulfills the obligations set out by the trait, since most of them are propagated.Intuitively, the concrete type encapsulated in the trait object already fulfills those obligationssince it implements the object’s trait. As long as the obligations don’t concern Self, then wecan assume that an implementation of the trait for its descriptor parameterized by the samenon-Self parameters and associated types fulfills them as well. However, if Self is men-tioned in a trait’s obligations then we must take care to make sure that the trait’s obligationsare fulfilled with Self instantiated with the descriptor.The primary obligation that an impl of a trait must fulfill is that the impl must providean implementation of the trait function. As such, we must also make sure that we can alwaysapply a trait function to a trait object whose descriptor implements the trait.Moreover, the trait obligations include three kinds of constraints that must be satisfied:• Supertrait constraints (SelfU :βs): These constraints are propagated and they al-low supertrait functions to be called on trait objects. Therefore, we must ensure thatthe trait descriptor implements each supertrait in the descriptor’s supertrait hierarchy.Thus, when an instance of a trait object is created, we verify that the object’s descrip-tor implements its trait and that it implements its supertraits, using the trait objectconstraint schemes output by rule (obj-trt).50• Associated type constraints (A :βa): These constraints are also propagated. In thiscase, however, the bounds are on an associated type, whose concrete instantiation isdetermined when a trait object is created. As such, we defer checking whether thoseconstraints are satisfied until then.• Other constraints (pih): These are additional constraints that impls of a trait mustsatisfy. The bounds in these constraints are applied on types other than the trait’s Selftype or its associated type. However, they are not propagated—they do not increase thepower or expressiveness of a trait object. As such, we do no extra work related to them.Building the trait object constraint schemesIn the side conditions pid = uobj : Dd 〈[uobj/SelfU]ud nn, Ad 7→ Xd〉din rule (obj-trt) we obtainthe constraints corresponding to traits in D’s supertrait hierarchy, which are used as theprincipal constraints of the rule’s output constraint schemes. The associated type in eachconstraint is instantiated with variable Xd, mirroring the associated type instantiations inthe object descriptor uobj. In the side condition Γ, X i, Xd |Θ | θd `os pid pid m we use the traitobject auxiliary relation to obtain the qualifying constraints of each trait object constraintscheme output by the rule. The side condition also includes constraint schemes θd, whichare the aformentioned trait object constraint schemes with their qualifying constraints pid mremoved: intuitively, to obtain the constraints pid m, we temporarily assume that the traitdescriptor already implements the traits in its supertrait hierarchy.The auxiliary relation Γ |Θ | θd `os uobj : D 〈ui, A 7→ X 〉 pis,pia is defined at the bottom offigure 5.7 (we will also refer to the relation as the relation `os for brevity). It relates theconstraint uobj : D 〈ui, A 7→ X 〉, where the trait D is part of the descriptor uobj’s supertraithierarchy, with constraints pis and pia that are type parameter-wise equivalent to the D’ssupertrait and associated type constraints. The side conditionsΓ |Θ | θd ` uobj : [uobj/SelfU][ui/X i]βsVpissΓ |Θ | θd ` AD 〈uobj,ui〉 : [uobj/SelfU][ui/X i]βaVpiaause a helper relation, defined earlier in the figure, that transforms the constraint on theleft-hand side of the arrow to some equivalent constraint that is well-formed with respectto the environments Γ and Θ (if the constraint on the left-hand side of the arrow is alreadywell-formed with respect to Γ,Θ then the relation may output the same constraint on theright-hand side of the arrow). The constraint schemes θd can be used in the proof of typeequality but not in the proof of well-formedness of the resulting constraints. The above sideconditions thus help ensure that the trait object constraint schemes output by (obj-trt) are51well-formed. For example, consider the following trait:trait D1 for SelfU { type AT : D2〈ADT1 〈SelfU〉〉; . . . }Its corresponding descriptor would be uobj = ∃T : D1〈ADT1 〈T〉 ∼ TA〉parameterized by thetype variable TA. If we build a corresponding trait object constraint scheme using the trait’sassociated type constraint directly without using the helper relation · | · | · ` ·V · then weobtain the constraint scheme∀TA.(ADT1 〈uobj〉 : D2〈ADT1 〈uobj〉〉)⇒ uobj : D1 〈AT 7→ TA〉 .The constraint is not well-formed because ADT1 〈uobj〉, which appears in the associated typeconstraint, is only well-formed if the constraint uobj : D1 〈AT 7→?〉 is satisfied (by rule(wf-atype)). To prove that, we need to use that same constraint scheme. Therefore, in therelation `os we can use the side conditionΓ,TA |Θ | ∀TA.uobj : D1 〈AT 7→ TA〉 ` ADT1 〈uobj〉 : D2〈ADT1 〈uobj〉〉V TA : D2〈TA〉,which gives us an associated type constraint TA : D2〈TA〉that is well-formed with respectto Γ and Θ (note that the constraint scheme ∀TA.uobj : D1 〈AT 〈uobj〉 7→ TA〉 lets us proveADT1 〈uobj〉 ∼ TA for all instantiations of the type variable TA). Intuitively, to obtain thequalifying constraints pis,pia of the trait object constraint schemes, we temporarily assumethat the trait descriptor already implements the traits in its supertrait hierarchy.Object-safe trait functionsThe relation `os also verifies that the trait function of the trait D, implemented for the de-scriptor uobj, is object-safe—that any application of the function to the descriptor’s objectpreserves type safety. The side conditionsΓ,T |Θ,θd,T : Dd 〈und, A ∼ Xd〉 [T/SelfU][u′i/X i]τR ∼ [uobj/SelfU][ui/X i]τR ,Γ,T |Θ,θd,T : Dd 〈und, A ∼ Xd〉 [uobj/SelfU][ui/X i]τm ∼ [T/SelfU][u′i/X i]τmmhelp ensure this, as we will see in chapter 7. They verify that the trait function’s argumentand return types, where SelfU is instantiated with the existential type variable T, are respec-tively equivalent to the argument and return types where SelfU is instantiated with the traitdescriptor uobj. The environments Γ and Θ are extended to ensure well-formedness of thetype expressions.To illustrate how these equality constraints can be satisfied when the function’s type sig-nature mentions an associated type contained in the trait object descriptor (forcibly param-52eterized by SelfU), consider the trait Iterator from page 47. The type scheme of its methodnext in MiniRust notation is∀SelfU.(SelfU : Iterator〈ItemT 7→?〉)⇒ fn(&SelfU)→ ItemTIterator 〈SelfU〉and its trait object descriptor isuobj =∃T : Iterator〈ItemTIterator 〈T〉 ∼T1〉 ,parametric over type variable T1. To satisfy the side conditions in the auxiliary relation, weneed to show thatΓ′ |Θ′ ItemTIterator 〈T〉 ∼ ItemTIterator 〈uobj〉where Γ′ and Θ′ are as follows:Γ′ =Γ, T, T1Θ′ =Θ, T : Iterator〈ItemT ∼T1〉 , ∀T1.(uOBJ : Iterator〈ItemT ∼T1〉)Using (c-ext) with constraint T : Iterator〈Item∼T1〉 and (eq-sep) we can proveΓ′ |Θ′ ItemTIterator 〈T〉 ∼T1.Using (c-ext) again with constraint uobj : Iterator〈ItemT ∼T1〉, and (eq-sep) with (eq-sym),we can proveΓ′ |Θ′ T1 ∼ ItemTIterator 〈uobj〉Then, we can compose the two equalities using (eq-trans) to obtain the desired result. Infact, as long as there are no overlapping impl declarations, the type equality constraints inthe auxiliary relation are satisfiable only when SelfU is a parameter to an associated type orwhen SelfU is in neither of the related types.5.3.2 DiscussionIn our formalization of object safety in MiniRust, we refrain from setting syntactic restric-tions on the appearances of the type variable Self in an object-safe declaration. Instead,we use the existing constraint mechanism of MiniRust’s type system to constrain object-safetraits in an attempt to allow as many object-safe traits as possible, without compromisingtype safety. As a result of this approach, the concept of object safety is two-tiered in MiniRust:the ability to create an instance of a trait object hinges on the trait declaration being object-safe (as decided by the rule (obj-trt)), and on the qualifying constraints in the correspondingtrait object constraint scheme being satisfied at object creation. Therefore, an object-safe53trait does not guarantee that all pointers to values that implement the trait can be safelycast to a trait object.For example, consider the following traits (the trait functions are omitted):trait D1 for SelfU { type AT : D2 〈SelfU〉 ; . . . }trait D2 〈U〉 for SelfU{ . . . }The object trait constraint scheme generated by the (obj-trt) rule for the trait D1 would be:∀TA.(TA : D2 〈uobj〉)⇒ uobj : D1 〈AT 7→TA〉where uobj =∃T : D1〈ADT1 〈T〉 ∼TA〉.Now suppose that D1 has the following impl:implD1 for i32 { type AT 7→ bool }and that the constraint bool : D2 〈i32〉 is satisfied. If we want to cast an i32 pointer to a traitobject of D1 (with descriptor uD1 = ∃T : D1〈ADT1 〈T〉 ∼ bool〉) then we must ensure that theconstraint bool : D2 〈uD1〉 is satisfied. To be able to create the trait object, the programmerwould also need to provide an impl corresponding to that constraint (unless the impl is auto-generated by the system, which we believe to be difficult, if at all possible).We conjecture that if in an object-safe trait we only let Self appear in associated typesthat normalize to concrete types that do not mention Self, then we should always be able tocreate an object of the trait (of course, instances of Self in the receiver position of the traitmethod signature would still be allowed and required). We can make the restriction morestrict by only allowing Self to appear as a parameter to an associated type that is in thetrait’s descriptor. Since such a restriction is defined at the syntactic level, it might be easierfor programmers to understand.54Chapter 6RustIn: an internal language forMiniRustOur formal study of Rust’s traits has so far only concerned its static semantics. Specifically,we have examined what constitutes a well-typed MiniRust program. To show how such aprogram behaves at run-time, we must develop its operational semantics. Designing opera-tional semantics for MiniRust directly is challenging in the presence of trait-based overload-ing. One way to solve this challenge is to translate MiniRust programs to another languagewhere trait constraints have been resolved. In this chapter, we present such a language—RustIn—for which we present a type system as well as operational semantics and we provethat RustIn is type-safe: that well-typed programs don’t exhibit undefined behavior. In chap-ter 7, we show how well-typed MiniRust programs can be translated to RustIn and we provethat the resulting RustIn programs are also well-typed.6.1 RustIn at a glanceOur approach to designing the internal language for MiniRust is similar to Haskell’s internallanguage, System FC [38]. System FC, based on System F, is designed to be explicitly-typedin the way that terms encode their typing derivations. System FC’s novel feature is supportfor non-syntactic type equality, in the form of coercions. In Haskell, coercions are used as theresult of translation of type equality constraints generated from associated type synonyms.Like System FC, RustIn is also explicitly typed. Our intention is to leave the bulk of thetypechecking to MiniRust. This leaves us with straightforward, syntax-directed typecheckingin RustIn and it lets us develop clear operational semantics that do not depend on the typeof a term.As MiniRust also includes the notion of equivalence of type expressions, we introduce co-ercions in RustIn. A coercion has a type that consists of the two equivalent type expressionsthat the coercion relates. For example, a coercion γ of type A 〈i32〉 ∼ bool relates the types55A 〈i32〉 and bool. We can also abstract over coercions as we do with terms in function dec-larations and with types in type abstractions. For example, the term Λ(c : A 〈i32〉 ∼ bool).eabstracts over some coercion variable c that has type A 〈i32〉 ∼ bool. Note, however, thatunlike most terms, coercions have no computation associated with them so they can, in prin-ciple, be erased at runtime.Coercions are used to convert the type of a term. For instance, if term e has type A 〈i32〉and coercion γ has type A 〈i32〉 ∼ bool then we can apply the coercion γ to term e to obtain aterm eI γ of type bool.Just as terms encode their typing derivations, coercions encode proofs of type expressionequivalence. Therefore, a coercion can be used to unambiguously reconstruct the proof ofequivalence of two type expressions.6.2 SyntaxFigure 6.1 presents the syntax of RustIn.6.2.1 ItemsAs in MiniRust, programs are collections of items. There are four kinds of items in RustIn.Type declarations type A 〈X 〉 are used to declare new abstract types or type aliases. Thetype constructor A is parameterized by zero or more types X .Axiom declarations are used to declare top-level type equivalence axioms, which can beused in coercions. Specifically, an axiom axiom c : ∀X .A 〈u〉 7→ u declares a new coercionconstant c and specifies its type. The axiom acts similarly to an axiom in proof theory—itis used to build proofs of type equivalence. Note that we restrict the left-hand side of thearrow 7→ in the axiom declaration to be an application of an abstract type declared in a typedeclaration. The universal quantifier ∀X is bound over both sides of the coercion type.Struct declarations define new structs as in MiniRust. RustIn structs are also used to rep-resent trait dictionaries, whose fields may include polymorphic functions. Therefore, unliketheir MiniRust counterparts, RustIn structs may include polymorphic fields.Term declarations are a generalization of top-level function declarations: they are used todeclare (possibly polymorphic) terms at the top level of the program. Similarly to MiniRust’sfunction declarations, the semantics of top-level terms are not affected by the order in whichthey are declared, as all top-level terms are visible at all points of the program. Thus, werestrict the top-level terms to be values, which do not reduce at runtime. The operationalsemantics, which we present later in the chapter, require one of the top-level variables to becalled main and have type fn()→ ().56e ∈ TERM, x, f ,main ∈VAR, lv ∈ LVAL, l ∈ LOC, cl ∈CLOC, v ∈VAL, w ∈ STOREVAL,pv ∈ PVAL, pw ∈ PSTOREVAL, τ ∈ STYPE, u ∈ TYPE, X ∈XVAR, T ∈ TVAR,U ∈UVAR, A ∈ACONS, AT ∈ TACONS, AU ∈UACONS, σ ∈ TSCHEME,η ∈USCHEME, γ ∈COER, c ∈CVAR, n ∈N+, ω ∈CTYPE, ϑ ∈ POLYCTYPE,µ ∈ LOC* STOREVALpgm ::= item (programs)item ::= type A 〈X 〉 | axiom c :∀X .A 〈u〉 7→ u (items)| struct S 〈X 〉 {x :σ} | x :σ= v;e ::= let x : τ= e in e | lv := e | e(e) | fn (x : τ){e} |&lv (terms)| ∗e | x | l | () | e; e | pack (τ, e,γ) as &(∃T,τ,ω)| let (T, x, c)= unpack e in e | S 〈u〉 {x : e} | e.x| e[u] |ΛX .e | eJγK |Λc :ω.e | eI γlv ::= x | ∗e | lv.x | cl (lvalues)cl ::= l | lI γ (c-locations)v ::= pvI γ | pv (values)pv ::= &l | () | fn (x : τ){e} | S 〈u〉 {x : v} (plain values)| pack (τ,v,γ) as τ |ΛX .e |Λc :ω.ew ::= pwI γ | pw (store values)pw ::= &l | () | fn (x : τ){e} | S 〈u〉 {x : l} (plain store values)| pack (τ,v,γ) as τ |ΛX .e |Λc :ω.eτ ::= () | T | AT 〈u〉 | fn(τ)→ τ |&u | S 〈u〉 (s-types)u ::= τ |U | AU 〈u〉 | (∃T,τ,ω) (types)X ::= T |U (type variables)A ::= AT | AU (abstract type constructors)σ ::= ∀X .σ | ∀ω.σ | τ (s-type schemes)η ::= ∀X .η | ∀ω.η | u (type schemes)γ ::= c | sym γ | γ◦γ | S 〈γ〉 |&γ | fn(γ)→ γ | () | X | A 〈γ〉 (coercions)| (∃T,γ,γ∼ γ) | ∗γ | spar (n,γ) | farg (n,γ) | fret γ| objf (τ,n,γ) | objc-l (τ,n,γ) | objc-r (τ,γ) | coer γ| coer-l (n,γ) | coer-r (n,γ) | γ[u] | ∀X .γ | ∀γ∼ γ.γω ::= u∼ u (simple coercion types)ϑ ::= η∼ η (polymorphic coercion types)Ω ::= Ω,type A 〈X 〉 |Ω,S 〈u〉 {x :σ} |Ω, c :ϑ | ;Γ ::= Γ, X |Γ, x :σ | ;Σ ::= Σ, l :σ | ;Figure 6.1: RustIn: syntax576.2.2 TermsThe syntax of terms in RustIn overlaps significantly with its counterpart in MiniRust. Anotable difference between the two is that RustIn terms are explicitly typed. For example,a let-expression let x : τ= e in e explicitly includes the type τ of the declared variable x. Theinstantiations of type parameters of a struct instance S 〈u〉 {x : e} are also explicitly includedin the term.New terms, not included in MiniRust, include:• anonymous functions fn (x : τ){e}, which are similar to Rust’s closures: they capture thevariables that are in their surrounding scope,• location l, which denote store locations that we use in our operational semantics (lo-cations are not, however, part of RustIn source programs—they are only introduced atruntime),• packing terms pack (τ, e,γ) as τ, which ‘pack’ the contents of the tuple (τ, e,γ) into anexistential object, where the type τ is existentially quantified,• unpacking terms let (T, x, c)= unpack e1 in e2, which bind the unpacked contents of theexistential object e1 to the variables of the tuple (T, x, c) in e2,• type abstractions ΛX .e, which abstract types X out of term e,• type applications e[u], which instantiate the type variables of a type abstraction withtypes u in term e,• coercion abstractions Λc :ω.e, which abstract coercions c of types ω out of term e, and• coercion applications eJγK, which instantiate the coercion variables of a coercion ab-straction with coercions γ in term e.• term coercions eI γ, which convert the type of term e using the coercion γ.Lvalues include c-locations, which in turn include store locations l, or coerced store lo-cations l I γ: locations that we want to use at a different type, specified by the coercion γ.Just like locations, c-locations are only introduced at runtime—they do not appear in sourceprograms.We also introduce values v, which range over terms that can be the final result of evalu-ation. They include plain values pv and coerced plain values pvI γ.Plain values include location references (&l), the unit expression (()), function declara-tions (fn (x : τ){e}), struct instances with value fields (S 〈u〉 {x : v}), value-saturated packingterms (pack (τ,v,γ) as τ), type abstractions ΛX .e, and coercion abstractions Λc :ω.e.58Store values w and plain store values pw range over values that can be stored directly inthe store. They are mostly the same as values and plain values with the exception of structinstances, where fields are store location labels instead values. Storing each struct instancefield in its own location allows us to directly reference it.6.2.3 TypesS-types τ and types u are for the most part the same as their MiniRust counterparts. Theonly exception is that the MiniRust trait descriptor ∃T : D 〈u,pi∼〉 is replaced in RustIn withthe more general existential object descriptor (∃T,τ,ω). We refer to a reference to a descriptor&(∃T,τ,ω) as an existential object (like a trait object in MiniRust, a RustIn existential objectis not exactly a pointer—the reference operator is thus overloaded). In the existential objectdescriptor, ∃T introduces the existentially quantified type variable T bound to the descriptor,τ are the types of terms encapsulated in the existential object and ω are the types of coercionsencapsulated in the object.As in MiniRust, X is a metavariable ranging over s-type variables T and type variablesU . A is a metavariable ranging over s-type constructors AT and type constructors AU thatare used to declare abstract types used in coercions.Type schemes in RustIn are not qualified, unlike their MiniRust counterparts. A RustIns-type scheme can be quantified over types ∀X i.σ (classifying type abstractions) and overcoercions ∀ω.σ (classifying coercion abstractions). We also include type scheme η, which isquantified over types that are not necessarily s-types. Note that the set of type schemesUSCHEME is a superset of the set of type schemes TSCHEME. Type substitutions are definedin the same way as in MiniRust—a substitution [u/T] is defined only if u ∈ STYPE.6.2.4 Coercionsγ ranges over coercions. We can separate them into the following categories:• c: a coercion variable introduced either in a top-level axiom (as a constant) or in acoercion abstraction,• sym γ and γ◦γ, which reflect respectively the symmetry and transitivity properties ofthe equivalence relation,• constructing coercions (S 〈γ〉 ,&γ, fn (γ) → γ, (), X , A 〈γ〉 , (∃T,γ,γ∼ γ),∀X .γ,∀γ∼ γ.γ),which are constructed following a type expression structure (they can also representreflexivity of the equivalence relation), and• deconstructing coercions, where the above coercions are decomposed (∗γ, spar (n,γ),farg (n,γ), fret γ, objf (τ,n,γ), objc-l (τ,n,γ), objc-r (τ,n,γ), coer γ, coer-l (n,γ),59coer-r (n,γ), γ[u]).ϑ is a polymorphic coercion type, which relates two equivalent type schemes η. We alsoinclude a simple coercion type, which relates two equivalent types u.6.2.5 EnvironmentsTo type terms, we carry around three distinct environments. The coercion and struct envi-ronment Ω contains coercion variable typings and defined structs. The typing environment Γcontains term variable typings and free type variables in scope. The store typing environmentΣ is a partial function mapping store locations to their types.We distinguish between environments Ω and Γ as the evaluation rules, which we discussin section 6.4, rely on the struct declarations and coercion typings that are contained inthe top-level environment Ω. Variable typings and the set of free type variables in scope,contained in the typing environment Γ, are not needed at runtime.6.3 Type system6.3.1 Well-typed coercionsFigures 6.2 and 6.3 present the well-typed coercions judgment. The judgment, Ω ` γ : ϑ,reads: “coercion γ has type ϑ under environment Ω”. An important insight into the judgmentis that every member of the set TYPE is also a member of the set COER. Specifically, a type uis also an identity coercion u of type u∼ u.Rule (co-var) simply looks up the type of a coercion variable (or constant) c in the envi-ronment Ω. Rules (co-sym) and (co-trans) apply the symmetry and transitivity propertiesof the equivalence relation respectively. (co-unit) and (co-tvar) are identity coercions of theunit type and type variables respectively. Rules (co-tabs), (co-cabs), (co-atype), (co-struct),(co-ref), (co-obj) and (co-fun) are used to type constructing coercions by induction on each ofthe respective coercion’s components. In each of those rules, if the coercions in the premisesare types, then the coercion in the conclusion of the rule is an identity coercion (relating atype to itself). Rule (co-tapp) is used for typing type applications γ[ui] where the type of γrelates two type schemes η1 and η2 quantified by some types X i.The typing rules in figure 6.3 are used to type deconstructing coercions. Such coercionsare parametric over some coercion γ that has a type that follows some specific structure. Forinstance, in rule (co-deref) used to type coercions of form ∗γ, the coercion γ relates referencetypes. In rule (co-spar), the coercion spar (n,γ) relates the nth type arguments of the structsrelated by the coercion γ. The coercions typed in rule (co-farg) and (co-fret) relate respectivelythe nth arguments and return types of the functions related by γ. Rules (co-objf), (co-objc-l)60Ω` γ :ϑ (Well-typed coercions)(co-var)(c :ϑ) ∈ΩΩ` c :ϑ (co-sym)Ω` γ : η1 ∼ η2Ω` sym γ : η2 ∼ η1(co-trans)Ω` γ1 : η1 ∼ η3 Ω` γ2 : η3 ∼ η2Ω` γ1 ◦γ2 : η1 ∼ η2(co-tabs)Ω` γ : η1 ∼ η2Ω`∀X i.γ :∀X i.η1 ∼∀X i.η2(co-tapp)Ω` γ :∀X i.η1 ∼∀X i.η2Ω` γ[ui] : [ui/X i]η1 ∼ [ui/X i]η2(co-cabs)Ω` γ : η1 ∼ η2 Ω` γ1 i : u1 i ∼ u3 i Ω` γ2 i : u2 i ∼ u4 iΩ`∀γ1 i ∼ γ2 i.γ : (∀u1 i ∼ u2 i.η1)∼ (∀u3 i ∼ u4 i.η2)(co-unit)Ω` () : ()∼ () (co-tvar) Ω` X : X ∼ X(co-atype)Ω` γi : u1 i ∼ u2 iΩ` A 〈γi〉 : A 〈u1 i〉 ∼ A 〈u2 i〉(co-struct)Ω` γi : u1 i ∼ u2 iΩ` S 〈γi〉 : S 〈u1 i〉 ∼ S 〈u2 i〉(co-ref)Ω` γ : u1 ∼ u2Ω`&γ :&u1 ∼&u2(co-obj)Ω` γi : τ1 i ∼ τ2 iiΩ` γ1 j : u1 j ∼ u3 jjΩ` γ2 j : u2 j ∼ u4 jjΩ` (∃T,γi,γ1 j ∼ γ2 j) : (∃T,τ1 i,u1 j ∼ u3 j)∼ (∃T,τ2 i,u2 j ∼ u4 j)(co-fun)Ω` γi : τ1 i ∼ τ2 i Ω` γ : τ1 ∼ τ2Ω` fn(γi)→ γ : fn(τ1 i)→ τ1 ∼ fn(τ2 i)→ τ2Figure 6.2: RustIn: well-typed coercionsand (co-objc-r) are used to type coercions that relate components of some pair of existentialobject descriptors. The coercions in the conclusion of these rules also include a type τ, whichinstantiates the type variable T over which the descriptor is existentially quantified. Finally,rules (co-coer), (co-coer-l) and (co-coer-r) are used to type coercions that relate components ofa type scheme quantified over a coercion.6.3.2 Well-typed termsThe well-typed terms judgment is presented in figure 6.4. The judgment, Ω | Γ | Σ ` e : σ,reads: “under environments Ω, Γ and Σ, term e has type scheme σ”. As opposed to the typingjudgments in MiniRust, the types of terms in RustIn may be polymorphic, which brings more61Ω` γ :ϑ (Well-typed coercions)(co-deref)Ω` γ :&u1 ∼&u2Ω`∗γ : u1 ∼ u2(co-spar)Ω` γ : S 〈u1 i〉 ∼ S 〈u2 i〉u1 = nth(u1 i) u2 = nth(u2 i)Ω` spar (n,γ) : u1 ∼ u2(co-farg)Ω` γ : fn(τ1 i)→ τR1 ∼ fn(τ2 i)→ τR2τ1 = nth(τ1 i) τ2 = nth(τ2 i)Ω` farg (n,γ) : τ1 ∼ τ2(co-fret)Ω` γ : fn(τ1 i)→ τ1 ∼ fn(τ2 i)→ τ2Ω` fret (γ) : τ1 ∼ τ2(co-objf)Ω` γ : (∃T,τ1 i,ω1 i)∼ (∃T,τ2 i,ω2 i) τ1 = [τ/T]nth(τ1 i) τ2 = [τ/T]nth(τ2 i)Ω` objf (τ,n,γ) : τ1 ∼ τ2(co-objc-l)Ω` γ : (∃T,τ1 i,u1 j ∼ u3 j)∼ (∃T,τ2 i,u2 j ∼ u4 j)u1 = [τ/T]nth(u1 j) u2 = [τ/T]nth(u2 j)Ω` objc-l (τ,n,γ) : u1 ∼ u2(co-objc-r)Ω` γ : (∃T,τ1 i,u1 j ∼ u3 j)∼ (∃T,τ2 i,u2 j ∼ u4 j)u1 = [τ/T]nth(u3 j) u2 = [τ/T]nth(u4 j)Ω` objc-r (τ,n,γ) : u1 ∼ u2(co-coer)Ω` γ :∀ω1 i.η1 ∼∀ω2 i.η2Ω` coer (γ) : η1 ∼ η2(co-coer-l)Ω` γ : (∀u1 i ∼ u2 i.η1)∼ (∀u3 i ∼ u4 i.η2) u1 = nth(u1 i) u2 = nth(u3 i)Ω` coer-l (n,γ) : u1 ∼ u2(co-coer-r)Ω` γ : (∀u1 i ∼ u2 i.η1)∼ (∀u3 i ∼ u4 i.η2) u1 = nth(u2 i) u2 = nth(u4 i)Ω` coer-r (n,γ) : u1 ∼ u2Figure 6.3: RustIn: well-typed coercions continuedflexibility as to where type and coercion abstractions are permitted. Note that we work withterms and types up to alpha-conversion (up to bound variable renaming). In particular, thismeans that [u/X ]∀X .σ is equivalent to [u/X ]∀X1.[X1/X ]σ (which in turn is equivalent to∀X1.[X1/X ]σ).Many of the rules are similar to their counterparts in MiniRust. Some notable differ-ences include (t-var), where the bound variables in the type scheme of x are not instantiatedright away. Type and coercion instantiations are explicit—the instantiations are part of theterm—and their corresponding typing rules are (t-tapp) and (t-capp) respectively. The coer-cion instantiation rule is similar to the function application rule (t-fapp), which demonstrates62Ω |Γ |Σ` e :σ (Well-typed terms)(t-let)Ω |Γ |Σ` e1 : τ1Ω |Γ, x : τ1 |Σ` e2 : τ2Ω |Γ |Σ` let x : τ1 = e1 in e2 : τ2(t-upd)Ω |Γ |Σ` lv : τΩ |Γ |Σ` e : τΩ |Γ |Σ` lv := e : ()(t-fapp)Ω |Γ |Σ` e : fn(τi)→ τΩ |Γ |Σ` e i : τiΩ |Γ |Σ` e(e i) : τ(t-fabs)Ω |Γ, xi : τi |Σ` e : τΩ |Γ |Σ` fn (xi : τi){e} : fn(τi)→ τ(t-ref)Ω |Γ |Σ` lv : τΩ |Γ |Σ`&lv :&τ (t-deref)Ω |Γ |Σ` e :&τΩ |Γ |Σ`∗e : τ (t-var)(x :σ) ∈ΓΩ |Γ |Σ` x :σ(t-unit)Ω |Γ |Σ` () : () (t-newstruct)S 〈X j〉 {xi :σi} ∈Ω Ω |Γ |Σ` e i : [u j/X j]σiiΩ |Γ |Σ` S 〈u j〉 {xi : e i} : S 〈u j〉(t-proj)Ω |Γ |Σ` e : S 〈u j〉S 〈X j〉 {xi :σi} ∈Ω (x :σ) ∈ xi :σiΩ |Γ |Σ` e.x : [u j/X j]σ(t-seq)Ω |Γ |Σ` e1 : τ1Ω |Γ |Σ` e2 : τ2Ω |Γ |Σ` e1; e2 : τ2(t-unpack)Ω |Γ |Σ` e1 :&(∃T,τi,ω j) Ω, c j :ω j |Γ,T, xi : τi |Σ` e2 : τ T 6∈ FV (τ)Ω |Γ |Σ` let (T, xi, c j)= unpack e1 in e2 : τ(t-pack)Ω |Γ |Σ` e i : [τ/T]τi i Ω` γ j : [τ/T]ω j jΩ |Γ |Σ` pack (τ, e i,γ j) as &(∃T,τi,ω j) :&(∃T,τi,ω j)(t-tapp)Ω |Γ |Σ` e :∀X i.σΩ |Γ |Σ` e[ui] : [ui/X i]σ(t-tabs)Ω |Γ, X i |Σ` e :σΩ |Γ |Σ`ΛX i.e :∀X i.σ(t-capp)Ω |Γ |Σ` e :∀ωi.σ Ω` γi :ωiΩ |Γ |Σ` eJγiK :σ (t-cabs) Ω, ci :ωi |Γ |Σ` e :σΩ |Γ |Σ`Λci :ωi.e :∀ωi.σ(t-loc)(l :σ) ∈ΣΩ |Γ |Σ` l :σ (t-coerce)Ω |Γ |Σ` e :σ1 Ω` γ :σ1 ∼σ2Ω |Γ |Σ` eI γ :σ2Figure 6.4: RustIn: well-typed terms63Ω |Γ` item :Ω |Γ (Well-typed items)(t-type)Ω |Γ` type A 〈X i〉 : [type A 〈X i〉] | ;(t-axiom)(type A 〈X i〉) ∈Ω [ui/X i] defined [A 7→ u] definedΩ |Γ` axiom c :∀X j.A 〈ui〉 7→ u : [c :∀X j.A 〈ui〉 ∼∀X j.u] | ;(t-struct)Ω |Γ` struct S 〈X i〉 {x j :σ j} : [S 〈X i〉 {x j :σ j}] | ;(t-decl)Ω |Γ | ; ` v :σΩ |Γ` x :σ= v; :; | [x :σ]` pgm :Ω |Γ (Well-typed programs)(t-pgm)Ω |Γ` itemi :Ωi |Γi Ω=Ωi Γ=Γi` itemi :Ω |ΓFigure 6.5: RustIn: well-typed items and programsthe likeness between coercions and terms.Rule (t-proj) is used for typing struct field projections, which can be polymorphic. Notethat rule (t-ref) only lets us have references to values that have a monomorphic s-type τ,so polymorphic struct fields cannot be referenced in RustIn (the restriction follows from thesemantics of Rust, where only monomorphic items can be referenced).Rule (t-pack) is used to type object packing terms, which create an instance of an exis-tential object. The rule (t-unpack) is used to type object unpacking terms. The side conditionT 6∈ FV (τ) ensures that the existential variable T does not escape its scope, delimited by theterm e2.Rule (t-loc), used for typing store locations, is the only rule that uses of the store typingenvironment Σ. There are no terms or items in the language that extend the store typingenvironment—the environment is a tool for proving type safety of RustIn in section 6.5.Finally, the rule (t-coerce) is used to type coerced terms, whose types are converted fromtype σ1 to σ2 as dictated by the type of the coercion γ.6.3.3 Well-typed items and programsFigure 6.5 presents the well-typed items and well-typed programs judgments. The judgmentsare similar to the analogous judgments in MiniRust. Of interest are (t-type) and (t-axiom),which are used for typing type and axiom declarations respectively. (t-type) simply populates64the environmentΩ with the name of the abstract type constructor, along with its parameters.In the side conditions of (t-axiom) we verify that the abstract type constructor A has beendeclared and that the abstract type’s parameters are instantiated with types of appropriatekind. The predicates [u/X ] defined and [A 7→ u] defined are the same as in MiniRust. Therule populates the environment Ω with the resulting coercion.6.4 Operational semanticsWe present the operational semantics of RustIn in the small-step (structural) style. We havetwo mutually dependent evaluation relations: one for evaluating terms, and another for eval-uating lvalues. We treat lvalues in a similar way as the Cyclone operational semantics [19].6.4.1 Evaluating termsThe relation 〈µ, e〉 Ω−−→ 〈µ, e〉, presented in figures 6.6 and 6.7, represents a single step ofcomputation in evaluating terms. The relation is parameterized by the top-level environmentΩ, which contains coercion typings and struct definitions. Throughout the evaluation ruleswe carry the store µ, which is a mapping from locations to store values.In RustIn, every term variable has a corresponding location in the store (this followsfrom Rust’s memory model where the data assigned to a local variable is stored directly onthe stack). For every variable declaration, we assign a location to the variable and in thedeclaration’s scope we substitute all instances of the variable with the location (the substitu-tion allows us to directly reference store locations). For instance, in rule (e-let1), in the sidecondition 〈µ′, l〉 = alloc(µ,v) we store the value v at location l (alloc is defined in figure 6.10).Then, in e2, we substitute all instances of the variable x with l. Similarly, for function callsin rule (e-fapp1), we allocate the values of the function arguments in locations l i and we sub-stitute the formal parameters xi with their respective locations in the body of the function.As such, locations l evaluate to the values to which they are mapped in the store, as shownin rule (e-loc). However, note that a reference to a location, &l is a value itself and cannot bereduced.In the evaluation relation we take special care when coercions are involved. In particular,we want to make sure that the evaluated term has the same type after every computationstep, as it is an important part of our type safety proof. For instance, we use rule (e-fapp2) toevaluate function applications where the function’s type is coerced by the coercion γ. We wantto get rid of the coercion γ so that we can apply the function to the arguments e i. However,we then need to coerce the types of the arguments e i so that they match with the argumenttypes τi that the function fn (xi : τi){e} expects. Therefore, we apply the coercions γi, whichwe create based on γ, to the arguments e i. Similarly, as we need the function application65〈µ, e〉 Ω−−→〈µ, e〉 (Evaluation of terms)(e-let1)〈µ′, l〉 = alloc(µ,v)〈µ, let x : τ= v in e2〉 Ω−−→〈µ′, [l/x]e2〉(e-upd1)〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉〈µ, lv := e〉 Ω−−→〈µ′, lv′ := e〉(e-upd2)〈µ, l := v〉 Ω−−→〈updateΩ(µ, l,v),()〉(e-upd3)〈µ, (lI γ) := e〉 Ω−−→〈µ, l := (eI sym γ)〉(e-loc)〈µ, l〉 Ω−−→〈µ,getValue(µ, l)〉(e-deref1)〈µ,∗&l〉 Ω−−→〈µ, l〉(e-deref2)〈µ,∗(&lI γ)〉 Ω−−→〈µ, lI∗γ〉(e-ref1)〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉〈µ,&lv〉 Ω−−→〈µ′,&lv′〉(e-ref2)〈µ,&(lI γ)〉 Ω−−→〈µ,&lI&γ〉(e-fapp1)µ0 =µ 〈µi, l i〉 = alloc(µi−1,vi)i〈µ, fn (xi : τi){e}(vi)〉 Ω−−→〈µi, [l i/xi]e〉(e-fapp2)γi = sym (farg (i,γ)) γR = fret (γ)〈µ, (fn (xi : τi){e}I γ)(e i)〉 Ω−−→〈µ, fn (xi : τi){e}(e i I γi)I γR〉(e-seq1)〈µ,v; e2〉 Ω−−→〈µ, e2〉(e-proj1)(x : v) ∈ xi : vi〈µ,S 〈u〉 {xi : vi}.x〉 Ω−−→〈µ,v〉(e-proj2)S 〈X j〉 {xi :σi} ∈Ω Ω` γ : S 〈u1 j〉 ∼ S 〈u2 j〉 γ j = spar ( j,γ)〈µ, (S 〈u1 j〉 {xi : vi}I γ).x〉 Ω−−→〈µ,S 〈u2 j〉 {xi : vi I Jγ j/X jKσi}.x〉(e-unpack1)µ0 =µ 〈µi, l i〉 = alloc(µi−1,vi)i〈µ, let (T, xi, c j)= unpack (pack (τ1,vi,γ j) as τ2) in e〉 Ω−−→〈µi, [l i/xi][τ1/T]e〉(e-unpack2)Ω` γ :&(∃T,τ1 i,ω1 j)∼&(∃T,τ2 i,ω2 j)γi = objf (τ1, i,∗γ) γ2 j = (sym (objc-l (τ1, j,∗γ)))◦γ1 j ◦objc-r (τ1, j,∗γ)j〈µ, let (T, xi, c j)= unpack ((pack (τ1,vi,γ1 j) as &(∃T,τ1 i,ω1 j))I γ) in e〉Ω−−→ 〈µ, let (T, xi, c j)= unpack (pack (τ1,vi I γi,γ2 j) as &(∃T,τ2 i,ω2 j)) in e〉... continued in figure 6.7Figure 6.6: RustIn: evaluation of terms66〈µ, e〉 Ω−−→〈µ, e〉 (Evaluation of terms)〈µ, e〉 Ω−−→〈µ′, e′〉(e-let2) 〈µ, let x : τ= e in e2〉 Ω−−→ 〈µ′, let x : τ= e′ in e2〉(e-upd4) 〈µ, l := e〉 Ω−−→ 〈µ′, l := e′〉(e-deref3) 〈µ,∗e〉 Ω−−→ 〈µ′,∗e′〉(e-fapp3) 〈µ, e(e)〉 Ω−−→ 〈µ′, e′(e)〉(e-fapp4) 〈µ, fn (x : τ){e1}(vi, e, e j)〉 Ω−−→ 〈µ′, fn (x : τ){e1}(vi, e′, e j)〉(e-seq2) 〈µ, e; e2〉 Ω−−→ 〈µ′, e′; e2〉(e-proj3) 〈µ, e.x〉 Ω−−→ 〈µ′, e′.x〉(e-struct) 〈µ,S 〈u〉 {xi : vi, x : e, x j : e j}〉 Ω−−→ 〈µ′,S 〈u〉 {xi : vi, x : e′, x j : e j}〉(e-tapp3) 〈µ, e[ui]〉 Ω−−→ 〈µ, e′[ui]〉(e-capp3) 〈µ, eJγK〉 Ω−−→ 〈µ, e′JγK〉(e-pack) 〈µ,pack (τ1,vi, e, e j,γ) as τ2〉 Ω−−→ 〈µ′,pack (τ1,vi, e′, e j,γ) as τ2〉(e-unpack3) 〈µ, let (T, x)= unpack e in e2〉 Ω−−→ 〈µ′, let (T, x)= unpack e′ in e2〉(e-coerce2) 〈µ, eI γ〉 Ω−−→ 〈µ′, e′I γ〉(e-tapp1)〈µ, (ΛX i.e)[ui]〉 Ω−−→〈µ, [ui/X i]e〉(e-tapp2)〈µ, ((ΛX i.e)I γ)[ui]〉 Ω−−→〈µ, [ui/X i]eI γ[ui]〉(e-capp1)〈µ, (Λci :ωi.e)JγiK〉 Ω−−→〈µ,Jγi/ciKe〉(e-capp2)γ′ = coer (γ) γ′i = coer-l (i,γ)◦γi ◦ sym (coer-r (i,γ))i〈µ, ((Λci :ωi.e)I γ)JγiK〉 Ω−−→〈µ,Jγ′i/ciKeI γ′〉(e-coerce1)〈µ, (pvI γ1)I γ2〉 Ω−−→〈µ, pvI (γ1 ◦γ2)〉Figure 6.7: RustIn: evaluation of terms continued67〈µ, lv〉 lv(Ω)−−−→〈µ, lv〉 (Evaluation of lvalues)(el-deref1)〈µ, e〉 Ω−−→〈µ′, e′〉〈µ,∗e〉 lv(Ω)−−−→〈µ′,∗e′〉(el-deref2)〈µ,∗&l〉 lv(Ω)−−−→〈µ, l〉(el-deref3)〈µ,∗(&lI γ)〉 lv(Ω)−−−→〈µ, lI∗γ〉(el-proj1)〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉〈µ, lv.x〉 lv(Ω)−−−→〈µ′, lv′.x〉(el-proj2)µ(l)= S 〈u j〉 {xi : l i} (x : l′) ∈ xi : l i〈µ, l.x〉 lv(Ω)−−−→〈µ, l′〉(el-proj3)µ(l)= S 〈u j〉 {xi : l i}I γ S 〈X j〉 {xi :σi} ∈Ω(x : τ) ∈ xi :σi γ j = spar ( j,γ) (x : l′) ∈ xi : l i〈µ, l.x〉 lv(Ω)−−−→〈µ, l′I Jγ j/X jKτ〉(el-proj4)µ(l)= S 〈u j〉 {xi : l i} S 〈X j〉 {xi :σi} ∈Ω(x : τ) ∈ xi :σi γ j = spar ( j,γ) (x : l′) ∈ xi : l i〈µ, (lI γ).x〉 lv(Ω)−−−→〈µ, l′I Jγ j/X jKτ〉(el-proj5)µ(l)= S 〈u j〉 {xi : l i}I γ2 S 〈X j〉 {xi :σi} ∈Ω(x : τ) ∈ xi :σi γ j = spar ( j,γ2 ◦γ1) (x : l′) ∈ xi : l i〈µ, (lI γ1).x〉 lv(Ω)−−−→〈µ, l′I Jγ j/X jKτ〉Figure 6.8: RustIn: evaluation of lvaluesterms on both sides of the relation to have the same types, we need to coerce the entire termusing γR , which we again obtain from deconstructing γ.6.4.2 Evaluating lvaluesSome rules of the term evaluation relation use in their premises the lvalue evaluation rela-tion 〈µ, lv〉 lv(Ω)−−−→ 〈µ′, lv′〉. Every step of this relation reduces an lvalue towards a c-location.We use the relation in the term evaluation rules (e-upd1) and (e-ref1). In rule (e-upd1) weuse the lvalue relation to reduce the left-hand side of the term lv := e to a c-location, so thatwe can update the resulting location with the value of e. In rule (e-ref1), where we evaluatea reference, we also use the lvalue relation to reduce the referenced lvalue to a location.The lvalue evaluation relation is presented in figure 6.8. Note that in rule (el-deref1) we68〈pgm〉 Ω−−→〈µ, e〉 (Evaluation of programs){ item }= { type,axiom,struct, xi :σi = vi } µ0 =; 〈µi, l i〉 = alloc(µi−1,vi)i〈item〉 Ω−−→〈[l i/xi]µi, [l i/xi]main()〉Figure 6.9: RustIn: evaluation of programsuse the term evaluation relation in its premise to reduce the term e. Rules (el-proj*) evaluatefield access lvalues lv.x. An lvalue lv.x intuitively reduces to the location of the field x of thestruct instance that is stored at the location represented by lv. In rules (el-proj3), (el-proj4)and (el-proj5) we add coercions to the resulting lvalues to ensure that their types match thetypes of the lvalues on the left-hand side of the relation. In the applied coercions Jγ j/X jKτthe double brackets J and K denote coercion substitutions: X j and τ are identity coercions inthis context. We use a similar substitution in the term evaluation relation in figure 6.6 inrule (e-proj2). Also note that only monomorphic fields are evaluated as lvalues. This is dueto the restriction in RustIn’s type system where we can only have references to monomorphicvalues and the update operation lv := e can only apply to monomorphic terms.6.4.3 Evaluating programsFigure 6.9 presents the program evaluation relation. The relation is defined by a single rule.As type, axiom and struct declarations don’t have any computation associated with them, weonly use top-level term declarations. In the rule’s side conditions we allocate the declaredvalues in the store and we substitute all top-level variable names with their correspondinglocations in the resulting store. Then we apply the main function, which we assume to be amember of the top-level variables xi.Note that the top-level terms need to already be values so that we can store them directlyin the store. Otherwise, as the top-level terms may be mutually dependent, we would need todo more work to determine their evaluation order, and reduce them to values before storingthem.6.4.4 Evaluation metafunctionsIn figure 6.10 we present metafunctions that we use throughout the evaluation rules forRustIn.The function alloc(µ,v) takes as inputs a store µ and a value v, and it outputs a tuple〈µ′, l〉 that contains a new location l where the value v is allocated and the updated store69alloc(µ,w) = 〈µ[l 7→w], l〉 where l 6∈ dom(µ)alloc(µ0,S 〈u〉 {xi : vi}) = 〈µi[l 7→ S 〈u〉 {xi : l i}], l〉 where 〈µi, l i〉 = alloc(µi−1,vi)il 6∈ dom(µi)alloc(µ0,S 〈u〉 {xi : vi}I γ) = 〈µi[l 7→ S 〈u〉 {xi : l i}I γ], l〉 where 〈µi, l i〉 = alloc(µi−1,vi)il 6∈ dom(µi)updateΩ(µ, l,w) = µ[l 7→w]updateΩ(µ0, l,S 〈u j〉 {xi : vi}) = µi where µ0(l)= S 〈u j〉 {xi : l i}µi =updateΩ(µi−1, l i,vi)updateΩ(µ0, l,S 〈u j〉 {xi : vi}) = µi where µ0(l)= S 〈u′j〉 {xi : l i}I γΩ` γ : S 〈u′j〉 ∼ S 〈u j〉S 〈X j〉 {xi :σi} ∈Ωγ j = spar ( j,sym γ)µi =updateΩ(µi−1, l i,vi II Jγ j/X jKσi)iupdateΩ(µ0, l,S 〈u j〉 {xi : vi}I γ) = µi where µ0(l)= S 〈u′j〉 {xi : l i}Ω` γ : S 〈u j〉 ∼ S 〈u′j〉S 〈X j〉 {xi :σi} ∈Ωγ j = spar ( j,γ)µi =updateΩ(µi−1, l i,vi II Jγ j/X jKσi)iupdateΩ(µ0, l,S 〈u j〉 {xi : vi}I γ) = µi where µ0(l)= S 〈u′j〉 {xi : l i}I γ′Ω` γ : S 〈u j〉 ∼ τΩ` γ′ : S 〈u′j〉 ∼ τS 〈X j〉 {xi :σi} ∈Ωγ j = spar ( j,γ◦ sym γ′)µi =updateΩ(µi−1, l i,vi II Jγ j/X jKσi)iundefined otherwisegetValue(µ, l) = S 〈u〉 {xi : getValue(µ, l i)} whereµ(l)≡ S 〈u〉 {xi : l i}getValue(µ, l) = S 〈u〉 {xi : getValue(µ, l i)}I γ whereµ(l)≡ S 〈u〉 {xi : l i}I γgetValue(µ, l) = µ(l) otherwise(pvI γ′)II γ = pvI (γ′ ◦γ)pvII γ = pvI γFigure 6.10: RustIn: metafunctions70µ′. If the allocated value is a store value w then the allocation is simple: a new location isselected from the outside of the domain of µ, the value w is stored at that location, and theupdated store that includes the new mapping is output by the function.When alloc is applied to a struct instance, then more work is required because a structinstance value is not a store value. In that case we recursively store the fields of the struct in-stance in new locations and we allocate the struct instance value—with the fields vi replacedwith their respective locations l i—in the resulting store. We proceed similarly with coercedstruct instances.Note that, strictly speaking, alloc is not a function, as it can choose any location l fromthe outside of the domain of the store, and there is nothing that prevents it from choosinga different location each time the function is applied to the same arguments. In fact, allocdefines a family of functions that are equivalent up to the choice of location labels. We usethe function in rules (e-let1), (e-fapp1) and (e-unpack1) in the evaluation relation in figure6.6, and in the program evaluation relation in figure 6.9.The function updateΩ(µ, l,v) is parameterized by the environment Ω. It takes as inputsa store µ, a location label l and a value v to be stored at l. We use the function update whenthe location l is already in the domain of µ and its type is the same as the type of the valuev (specifically, we use it in rule (e-upd2) in the evaluation relation in figure 6.6). The outputof the function is an updated store µ′, where the value at location l is modified accordingly.When the input value is a store value w, then the update operation is straightforward. Whenthe input value is a struct instance, then the exact store value chosen to update the store atlocation l depends on what is the existing store value at that location. To preserve the typesof the affected locations, we may have to apply coercions to the stored values. Note that theupdate function also reuses the same locations for struct fields.In the definition of update we use the binary helper function II defined at the bottomof the figure. We can interpret the helper function as a “value-preserving coercion”. Thefunction takes as inputs a value and a coercion, and it outputs the application of the coercionon the input value. If the input value is a coerced plain value pvI γ′ then when we apply γto it, we obtain (pvI γ′)I γ, which is not a value. The function (pvI γ′)II γ thus takes anevaluation step, composing the coercions γ′ and γ so that its result pvI (γ′◦γ) is a value. Weuse the helper function in recursive calls to the update function to ensure that we apply thefunction to a value in accordance with its domain.The function getValue takes as inputs a store µ and a location l, and it outputs a valuev corresponding to the store value stored at location l in µ. If the stored value is a structinstance, then its fields are locations (and not values), so we recursively apply getValue onthe struct’s fields’ locations to obtain the appropriate values. We use the function in rule(e-loc) of the evaluation relation in figure 6.6 to obtain the value stored at location l.716.5 Type safetyHaving defined the operational semantics for RustIn, we can reason about the type safety ofwell-typed programs. Before we present the relevant theorems, we first set up some defini-tions.We first define a relation parametric on the store µ. The relation defines an ordering onstore values related by struct instances that occur in µ.Definition 6.1. Let Aµ = {w | ∃l.µ(l)=w}. In other words, Aµ is the image of µ.Define @µ ⊆ Aµ×Aµ as follows:• µ(l)@µ S 〈u〉 {xm : ln, x : l, xn : ln}• µ(l)@µ S 〈u〉 {xm : ln, x : l, xn : ln}I γThen we introduce the notion of a well-typed store.Definition 6.2 (Well-typed store). We say that Ω | Γ | Σ ` µ, meaning that the store µ is welltyped with respect to the environments Ω,Γ and the store typing Σ if1. dom(µ)= dom(Σ) and2. Ω |Γ |Σ`µ(l) :Σ(l) for every l ∈ dom(µ)3. @µ is a well-founded relation on the set Aµ = {w | ∃l.µ(l) = w}, i.e., it has no infinitedescending chains.Note that the definition requires the relation @µ to be well-founded. Intuitively, thismeans that the store should not contain circular struct instances where, for example, a fieldof a struct instance is that particular struct instance itself. In particular, this is required toensure that the metafunctions getValue and update are terminating.1The concept of type equality axiom consistency, is another important piece of type safetyof RustIn. Its definition is adapted from System FC [38] whose type safety proof also relieson axiom consistency. The definition uses a notion of constructed types (called value types inSystem FC), defined below.Definition 6.3 (Constructed type). A constructed type is a type η that is of the form(),S 〈u〉 , fn(τ)→ τ,&u, (∃T,τ,ω), ∀X i.η or ∀ωi.η.Roughly speaking, a constructed type is a type whose outermost type constructor is someconcrete type, i.e., a constructed type is neither an abstract type nor a type variable.1Note that a struct instance may still contain a pointer to itself. For example, the assignment: x0 := S{x :&x0},where S is a struct type constructor, is allowed.72Definition 6.4 (Consistency of coercion environment Ω). We say that Ω is consistent if thefollowing hold:1. If Ω` γ : S 〈u〉 ∼ η and η is a constructed type then η= S 〈u′〉 for some u′.2. If Ω` γ : fn(τi)→ τ∼ η and η is a constructed type then η= fn(τ′i)→ τ′ for some τ′i,τ′.3. If Ω` γ :&u1 ∼ η and η is a constructed type then η=&u′1 for some u′1.4. If Ω` γ : (∃T,τi,ω j)∼ η and η is a constructed type then η= (∃T,τ′i,ω′j) for some τ′i,ω′j.5. If Ω` γ :∀X i.σ∼ η′ where η′ is any type, then η′ =∀X i.σ′ for some σ′.6. If Ω` γ :∀ωi.σ∼ η′ where η′ is any type, then η′ =∀ω′i.σ′ for some ω′i,σ′.A consistent environment Ω prevents us from being able to conclude inconsistent typeequalities such as i32∼ bool.We can now state the theorems that together demonstrate type safety of RustIn. We firstprove that if a well-typed term steps to another term then both terms have the same type.Theorem 6.1 (Preservation). Suppose Ω is a consistent environment.1. If Ω |Γ |Σ` e :σ and Ω |Γ |Σ`µ and 〈µ, e〉 Ω−−→〈µ′, e′〉then, there is some store typing Σ′ ⊇Σ such thatΩ |Γ |Σ′ ` e′ :σ and Ω |Γ |Σ′ `µ′.2. If Ω |Γ |Σ` lv : τ and Ω |Γ |Σ`µ and 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉then, there is some store typing Σ′ ⊇Σ such thatΩ |Γ |Σ′ ` lv′ : τ and Ω |Γ |Σ′ `µ′.The second part of the type safety proof is the proof of progress, which roughly says thata well-typed term is either a value or it can be reduced. In other words, a well-typed termdoesn’t get ‘stuck’.Theorem 6.2 (Progress). Suppose Ω is a consistent environment.1. If Ω | ; | Σ ` e : σ then either e ∈ VAL or, for any store µ such that Ω | ; | Σ ` µ, there issome term e′ and store µ′ with 〈µ, e〉 Ω−−→〈µ′, e′〉2. If Ω | ; |Σ` lv : τ then either lv ∈CLOC or, for any store µ such that Ω | ; |Σ`µ, there issome lvalue lv′ and store µ′ with 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉The previous two theorems together paint the type safety picture of MiniRust, statingthat, unless evaluation diverges, every well-typed term reduces to a value with all typespreserved.73The last theorem we present concerns the program evaluation rule. It roughly statesthat if a program is well-typed, produces a consistent environment Ω and contains the mainfunction, then we can successfully take a type-preserving evaluation step.Theorem 6.3. Suppose ` pgm :Ω |Γ where Ω is consistent and Γ= {xi :σi}.If (main : fn()→ ()) ∈Γ, then there are some µ, e, Σ for which〈pgm〉 Ω−−→〈µ, e〉, and Ω | ; |Σ`µ, and Ω | ; |Σ` e : ().The proofs of the above theorems and all helper lemmas are found in appendix A.74Chapter 7Translating MiniRust programs toRustInRust traits introduce type-based overloading to the language, where the runtime semanticsof overloaded terms depend on the types at which the terms are used. As mentioned in theprevious chapter, defining the operational semantics directly in languages with type-basedoverloading is challenging. For instance, to define them directly in MiniRust, we would needto somehow encode impl lookup in the semantics to resolve constraints. A simpler way todo this, which is how Haskell type classes are implemented [16], is through translation toan internal language where the trait constraints have already been resolved. As such, inthe previous chapter, we developed an internal language, RustIn, which doesn’t have traits,and we provided operational semantics and a proof of type safety for it. In this chapter weshow how MiniRust programs can be translated to RustIn programs. The translation thatwe present here is type-directed: the translation of a term is decided in part by its type.As such, we present the translation rules by extending the MiniRust typing rules presentedin chapter 5. We then prove that the translation preserves well-typedness, which brings uscloser to proving that MiniRust is type-safe.7.1 Translation at a glanceThe salient part of the type-directed translation from MiniRust to RustIn is the way in whichconstraints are translated. Satisfied MiniRust constraints translate to some expressionsthat provide evidence of constraint entailment [20]. In MiniRust, terms with qualified typescan only be used if their qualifying constraints are entailed by the constraint environment.In turn, the RustIn translations of such terms are abstracted over the evidence that theirqualifying constraints are satisfied. Having the evidence in the translation of a qualified termaligns with the explicit nature of expressions in our target language, RustIn, where terms75encode their typing derivation and coercions encode proof of equivalence of type expressions.Recall that MiniRust trait constraints have form u : D 〈ui, A 7→ uA〉. For the purposeof translation we consider such constraints as combinations of a simple trait constraintu : D 〈ui〉 and an equality constraint AD 〈u,ui〉 ∼ uA. As such, the translation of an extendedconstraint produces two pieces of evidence.The evidence of trait constraint entailment in RustIn takes the form of a dictionarythat contains the trait function and the dictionaries corresponding to the trait’s supertraitsand associated type constraints. The dictionary is implemented using a RustIn struct. AMiniRust function that is qualified by one or more trait constraints is then translated to ahigher-order function that takes as additional inputs the dictionaries corresponding to thequalifying constraints. Similarly, a MiniRust trait function is translated to a higher-orderfunction that takes as input the dictionary corresponding to an impl of the trait. In the bodyof the function we take the appropriate concrete function from the input dictionary and applyit.The evidence of equality constraint entailment in RustIn takes the form of a coercion.Recall that a RustIn coercion already encodes in it the proof of type equivalence of the twotype expressions that it relates. An equality constraint entailment derivation then constructsthe corresponding coercion. A MiniRust term qualified by an equality constraint (or ratherby an extended constraint that contains an associated type instantiation) is translated to acoercion abstraction. To use the resulting RustIn term, we apply it to the concrete coercionthat represents a proof of type equality.We use RustIn abstract types to serve as translation targets of associated types. As such,an associated type declaration in a trait declaration is translated to an abstract type decla-ration and an associated type instantiation in an impl is translated to a type equality axiom.7.2 SyntaxThe formalization in this chapter relates two languages: MiniRust and RustIn. We use thesyntax of both, presented in figures 5.1 and 6.1 respectively. Since the syntactic constructs inthe two languages overlap, we add a superscript t to RustIn constructs.To aid with the translation, we modify the MiniRust typing and constraint environments.The modified environments are defined below (new parts are highlighted):Γ ::= ; |Γ, x :σ |Γ, X |Γ,S 〈X 〉 {x : τ} (typing environments)| Γ, (D 〈X 〉where pi,Self :β x , A :β x , f ,obj)Θ ::= ; |Θ,θ 〈x, c〉 (constraint environments)The trait information tuple in the typing environment Γ is extended with the names of76the dictionary fields that correspond to the trait’s supertrait and associated type constraints.Specifically, in a trait information tuple (D 〈X i〉where pi,Self : βs xs, A : βa xa, f ,obj), thevariables xs, xa are field names of the RustIn struct that represents the dictionary of thetrait D. Specifically, xs correspond to fields that contain its supertrait dictionaries and xacorrespond to fields that contain dictionaries that represent D’s associated type constraints.The constraint environment Θ is extended to bind constraint schemes to RustIn term andcoercion variables. The variables correspond to the translations of the constraint schemes inthe resulting RustIn program.7.3 Translating typesWe extend the MiniRust well-formedness judgments to translate MiniRust types (and typeschemes) as well as constraints (and constraint schemes) to RustIn types. Figure 7.1 presentsthe judgments. We read the well-formed types relation, Γ |Θ`WF u ut, as “under environ-ments Γ and Θ, a well-formed MiniRust type u translates to RustIn type ut”. Most of thetranslation rules are straightforward. The most interesting rule in the relation is (wf-desc),used to translate trait object descriptors. MiniRust trait object descriptors translate to themore general RustIn existential object descriptors. The translation makes evident that atrait object encapsulates a reference to the concrete value that implements the object’s traitand the dictionary SD 〈T,uti〉 corresponding to the object’s underlying concrete impl. The ex-istential object also encapsulates coercions that correspond to the associated type equalitiesin the descriptor.Note that in the premises of rule (wf-desc) and (wf-tscheme) we extend the dictionary en-vironment Θ with some constraints without providing their corresponding translation vari-ables. The translation variables are not used in the well-formedness judgments so we simplyomit them to simplify the presentation. Similarly, in the premise Γ |Θ u : D 〈ui, A 7→?〉 ofrule (wf-atype) we omit the translation of the constraint since we do not use it.The well-formed constraint schemes judgment Γ |Θ `WF θ 〈σt,ϑ〉 is used to obtain thetypes of the evidence produced by the constraint scheme θ. The resulting translation is atuple that consists of the type scheme σt of the trait constraint portion of the constraintscheme and a polymorphic coercion type ϑ corresponding to the coercion that representsthe equality constraint. Note that the identity associated type instantiation A 7→ ? in rule(wf-trcons) translates to an identity coercion.7.4 Translating constraintsFigure 7.2 presents the constraint entailment judgments with translation. In the trait con-straint entailment judgment, Γ |Θ pi 〈et,γ〉, a satisfied trait constraint pi is translated to77Γ |Θ`WF u ut (Well-formed types)(wf-var)X ∈ΓΓ |Θ`WF X X(wf-unit)Γ |Θ`WF () ()(wf-fun)Γ |Θ`WF τi τti Γ |Θ`WF τ τtΓ |Θ`WF fn(τi)→ τ fn(τti)→ τt(wf-ref)Γ |Θ`WF u utΓ |Θ`WF &u &ut(wf-struct)Γ` S 〈ui〉Γ |Θ`WF ui utiΓ |Θ`WF S 〈ui〉 S 〈uti〉(wf-atype)Γ |Θ u : D 〈ui, A 7→?〉Γ |Θ`WF u ut Γ |Θ`WF ui utiΓ |Θ`WF AD 〈u,ui〉 AD 〈ut,uti〉(wf-desc)Γ`D obj-safe Γ` SelfU : D 〈ui〉 Γ |Θ`WF ui utiΓ,T |Θ,T : D 〈ui〉 `WF AD j 〈T,us j〉 AD j 〈T,uts j〉jΓ |Θ`WF u j utjΓ |Θ`WF ∃T : D〈ui, AD j 〈T,us j〉 ∼ u j〉 (∃T,&T,SD 〈T,uti〉 , AD j 〈T,uts j〉 ∼ utj)Γ |Θ`WF σ σt (Well-formed type schemes)(wf-tscheme)Γ, X i |Θ,pi j `WF pi j 〈τtj,ω j〉jΓ, X i |Θ,pi j `WF τ τtΓ |Θ`WF ∀X i.pi j ⇒ τ ∀X i.∀ω j.fn(τtj)→ τtΓ |Θ`WF θ 〈σt,ϑ〉 (Well-formed constraint schemes)(wf-cscheme)Γ, X i |Θ,pi j `WF pi j 〈τtj,ω j〉jΓ, X i |Θ,pi j `WF pi 〈τt,ut1 ∼ ut2〉Γ |Θ`WF ∀X i.pi j ⇒pi 〈∀X i.∀ω j.fn(τtj)→ τt,∀X i.ut1 ∼∀X i.ut2〉(wf-treqcons)Γ` u : D 〈ui〉 Γ` ADΓ |Θ`WF u ut Γ |Θ`WF ui uti Γ |Θ`WF uA utAΓ |Θ`WF u : D 〈ui, A 7→ uA〉 〈SD 〈ut,uti〉 , AD 〈ut,uti〉 ∼ utA〉(wf-trcons)Γ` u : D 〈ui〉 Γ` AD Γ |Θ`WF u ut Γ |Θ`WF ui utiΓ |Θ`WF u : D 〈ui, A 7→?〉 〈SD 〈ut,uti〉 , AD 〈ut,uti〉 ∼ AD 〈ut,uti〉〉Figure 7.1: MiniRust: well-formedness judgments with translation78Γ |Θpi 〈et,γ〉 (Trait constraint entailment)(c-ext)(∀X i.pi j ⇒pi 〈x, c〉) ∈Θ Γ |Θ`WF ui uti Γ |Θ [ui/X i]pi j 〈etj,γ j〉Γ |Θ [ui/X i]pi 〈x[uti]Jγ jK(etj), c[uti]〉(c-treq1)Γ |Θ u1 : D 〈u1 i, A 7→ u3〉 〈et,γ1〉 Γ` u2 : D 〈u2 i〉Γ |Θ u1 ∼ u2 γ2 Γ |Θ u1 i ∼ u2 i γiiΓ |Θ u3 ∼ u4 γ3Γ |Θ u2 : D 〈u2 i, A 7→ u4〉 〈etI SD 〈γ2,γi〉 , AD 〈sym (γ2),sym (γi)〉◦γ1 ◦γ3〉(c-treq2)Γ |Θ u1 : D 〈u1 i, A 7→?〉 〈et,γ1〉 Γ` u2 : D 〈u2 i〉 Γ |Θ u1 ∼ u2 γ2Γ |Θ u1 i ∼ u2 i γiiΓ |Θ`WF u2 ut2 Γ |Θ`WF u2 i ut2 iΓ |Θ u2 : D 〈u2 i, A 7→?〉 〈etI SD 〈γ2,γi〉 , AD 〈ut2,ut2 i〉〉(c-astar)Γ |Θ u : D 〈ui, A 7→ uA〉 〈et,γ〉 Γ |Θ`WF u ut Γ |Θ`WF ui utiΓ |Θ u : D 〈ui, A 7→?〉 〈et, AD 〈ut,uti〉〉Γ |Θ u∼ u γ (Equality constraint entailment)(eq-sep)Γ |Θ u : D 〈ui, A 7→ uA〉 〈et,γ〉Γ |Θ AD 〈u,ui〉 ∼ uA γ(eq-refl)Γ |Θ`WF u utΓ |Θ u∼ u ut(eq-trans)Γ |Θ u1 ∼ u3 γ1Γ |Θ u3 ∼ u2 γ2Γ |Θ u1 ∼ u2 γ1 ◦γ2(eq-sym)Γ |Θ u2 ∼ u1 γΓ |Θ u1 ∼ u2 sym (γ)(eq-struct)Γ` S 〈u1 i〉 Γ` S 〈u2 i〉Γ |Θ u1 i ∼ u2 i γiiΓ |Θ S 〈u1 i〉 ∼ S 〈u2 i〉 S 〈γi〉(eq-ref)Γ |Θ u1 ∼ u2 γΓ |Θ&u1 ∼&u2 &γ(eq-fun)Γ |Θ τ1 i ∼ τ2 i γiiΓ |Θ τ1 ∼ τ2 γΓ |Θ fn(τ1 i)→ τ1 ∼ fn(τ2 i)→ τ2 fn(γi)→ γ(eq-atype)Γ` u1 : D 〈u1 i〉 Γ` u2 : D 〈u2 i〉 Γ |Θ u1 ∼ u2 γ Γ |Θ u1 i ∼ u2 i γiΓ |Θ AD 〈u1,u1 i〉 ∼ AD 〈u2,u2 i〉 AD 〈γ,γi〉(eq-obj)Γ` SelfU : D 〈u1 i〉 Γ` SelfU : D 〈u2 i〉 Γ`T : D j 〈u1s j s〉jΓ`T : D j 〈u2s j s〉jΓ |Θ u1 i ∼ u2 i γi Γ,T |Θ,T : D 〈u1 i〉 u1s j ∼ u2s j γs j Γ |Θ u1 j ∼ u2 j γ jΓ |Θ ∃T : D 〈u1 i, AD j 〈T,u1s j〉 ∼ u1 j〉 ∼ ∃T : D 〈u2 i, AD j 〈T,u2s j〉 ∼ u2 j〉 (∃T,&T,SD 〈T,γi〉 , AD j 〈T,γs j〉 ∼ γ j)Figure 7.2: MiniRust: constraint entailment with translation79a term et and a coercion γ, representing the constraint’s trait and equality parts respectively.In rule (c-ext), the side condition (∀X i.pi j ⇒ pi 〈x, c〉) ∈Θ gives us the variables x and cthat correspond to the translation of the constraint scheme ∀X i.pi j ⇒ pi. The term variablex represents a higher-order function quantified by type variables X i and abstracted overthe evidence expressions corresponding to the constraints pi j. In the conclusion of the rule,the translation dictionary term, x[uti]Jγ jK(etj), instantiates x with types uti and applies theresult to the evidence of entailment of constraints [ui/X i]pi j (in the form of coercions γ j anddictionary terms etj). The resulting coercion in the conclusion of the rule is the constraintscheme’s coercion variable c instantiated with types uti—qualifying constraints pi j are notpart of the translation of the equality part of the constraint. In rule (c-treq2), the identityassociated type instantiation A 7→ ? simply translates to an identity coercion AD 〈ut2,ut2 i〉(recall that the representations of RustIn types also represent identity coercions).In the equality constraint entailment relation, Γ | Θ u ∼ u γ, we translate equalityconstraints to coercions. The language of coercions in RustIn lets us encode the proof ofequivalence of type expressions directly in the resulting coercion.7.5 Translating termsFigure 7.3 presents the well-typed terms judgment with translation. The translation of termsis fairly straightforward. Note that, since terms in the target language are explicitly typed,translations of MiniRust terms contain additional information from their types (such as inrules (let-un), (var) and (new-struct)).In rule (var), if the term variable x has a qualified type scheme in the typing environmentΓ, then its type scheme’s type variables must be instantiated and its qualifying constraintssatisfied before we can use x. As such, the translation of x includes explicit application of thetype scheme’s type variables and of the evidence expressions that correspond to the qualifyingconstraints pi j.In rule (obj-cast) we translate trait object instantiations to existential object packingterms. In the premise Γ | Θ (∃T : D 〈ui,u1 j ∼ u2 j〉) : D 〈ui〉 we omit the translation of theconstraint because we do not need it.7.6 Translating itemsFigure 7.4 presents the well-typed items judgment with translation. In the judgment,Γ |Θ` item :Γ |Θ pgmt, an item translates to a partial program (a collection of items). Thetranslation of struct declarations in rule (struct) is straightforward. Function declarationsin (fun) translate to top-level term declarations. If a MiniRust function is qualified by con-straints pi j in its where-clause, then the resulting function in RustIn is abstracted over the80Γ |Θ` e : τ et (Well-typed terms)(sub)Γ |Θ` e : τ1 et Γ |Θ τ1 ∼ τ2 γΓ |Θ` e : τ2 etI γ(as)Γ |Θ` e : τ etΓ |Θ` e as τ : τ et(unit)Γ |Θ` () : () () (let-un)Γ |Θ` e1 : τ1 et1Γ, x : τ1 |Θ` e2 : τ2 et2 Γ |Θ`WF τ1 τtΓ |Θ` let x= e1 in e2 : τ2 let x : τt = et1 in et2(seq)Γ |Θ` e1 : τ1 et1Γ |Θ` e2 : τ2 et2Γ |Θ` e1; e2 : τ2 et1; et2(var)(x :∀X i.pi j ⇒ τ) ∈ΓΓ |Θ`WF ui uti Γ |Θ [ui/X i]pi j 〈etj,γ j〉jΓ |Θ` x : [ui/X i]τ x[uti]Jγ jK(etj)(app)Γ |Θ` e : fn(τi)→ τ etΓ |Θ` e i : τi etiΓ |Θ` e(e i) : τ et(eti)(ref)Γ |Θ` lv : τ lvtΓ |Θ`&lv :&τ &lvt(deref)Γ |Θ` e :&τ etΓ |Θ`∗e : τ ∗et(asgn)Γ |Θ` lv : τ lvtΓ |Θ` e : τ etΓ |Θ` lv := e : () lvt := et(new-struct)S 〈Xk〉 {xi : τi} ∈Γ Γ |Θ` e i : [uk/Xk]τi eti Γ |Θ`WF uk utkΓ |Θ` S{xi : e i} : S 〈uk〉 S 〈utk〉 {xi : eti}(proj)Γ |Θ` e : S 〈u j〉 et S 〈X j〉 {xm : τm, x : τ, xn : τn} ∈ΓΓ |Θ` e.x : [u j/X j]τ et.x(obj-cast)Γ |Θ` e :&τ et Γ |Θ`WF τ τt1Γ |Θ τ : D 〈ui〉 etD Γ |Θ [τ/T]u1 j ∼ u2 j γ jΓ |Θ (∃T : D 〈ui,u1 j ∼ u2 j〉) : D 〈ui〉 Γ |Θ`WF ∃T : D 〈ui,u1 j ∼ u2 j〉 τt2Γ |Θ` e :&(∃T : D 〈ui,u1 j ∼ u2 j〉) pack (τt1, et, etD ,γ j) as τt2Figure 7.3: MiniRust: well-typed terms with translation81Γ |Θ` item :Γ |Θ pgmt (Well-typed items)(struct)Γ, X j |Θ`WF τi τtiiΓ |Θ` struct S 〈X j〉 {xi : τi} : [S 〈X j〉 {xi : τi}] | ; struct S 〈X j〉 {xi : τti}(fun)σ=∀Xk.pi j ⇒ fn(τi)→ τ Γ |Θ`WF σ σtσt =∀Xk.∀ω j .fn(τtj)→ fn(τti)→ τt Γ, Xk, xi : τi |Θ,pi j 〈x j , c j〉 ` e : τ etΓ |Θ` fn f 〈Xk〉 (xi : τi)→ τwhere pi j { e } : [ f :σ] | ; f :σt =ΛXk.Λc j :ω j .fn (x j : τtj){ fn (xi : τti){ et } }(trait){pi j}≡ {(Self :βs),pih} X p =Self, X i Γ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒pihhσ=∀Xk.pil ⇒ fn(τm)→ τR σ′ =∀X p.(Self : D 〈X i〉)⇒σ Γ |Θ`WF σ′ σ′tΓ, X p |Θ,Self : D 〈X i〉 `WF σ σt σt =∀Xk.∀ωl .fn(τtl )→ fn(τtm)→ τtRΓ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒Self :βs 〈∀X p.fn(SD 〈X p〉)→ τts,ϑs〉sΓ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈∀X p.fn(SD 〈X p〉)→ τta,ϑa〉aΓ |Θ`trait D 〈X i〉 for Selfwhere pi j {type A :βa;f :σ; }:[(D 〈X i〉where pih, Self :βs xs, A :βa xa, obj-unsafe), f :σ′] |[∀X p.(Self : D 〈X i〉)⇒Self :βs 〈xD,s, cD,s〉s,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈xD,a, cD,a〉a] type AD 〈X p〉 ; axiom cD,a :ϑaa; axiom cD,s :ϑss; struct SD 〈X p〉 { f :σt, xs : τts, xa : τta}f :σ′t =ΛX p, Xk.Λcl :ωl .fn (xD : SD 〈X p〉 , xl : τtl ){ (xD . f )[Xk]JclK(xl ) };xD,s :∀X p.fn(SD 〈X p〉)→ τts =ΛX p.fn (xD : SD 〈X p〉){xD .xs};sxD,a :∀X p.fn(SD 〈X p〉)→ τta =ΛX p.fn (xD : SD 〈X p〉){xD .xa};a(impl)(D 〈X i〉where pih, Self :βs xss, A :βa xaa, f ,_) ∈Γ up = u,ui X p =Self, X iXk ∈ FV (up) Θ∗ =Θ\{∀X p.(Self : D 〈X i〉)⇒Self :βs _s,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa _a}Γ, Xk |Θ∗,pi j 〈x j , c j〉 [up/X p](Self :βs) 〈ets,γs〉sΓ, Xk |Θ∗,pi j 〈x j , c j〉 [up/X p]pihhΓ, Xk |Θ∗,pi j 〈x j , c j〉 `WF uA utA Γ, Xk |Θ∗,pi j 〈x j , c j〉 (AD 〈up〉 : [up/X p]βa) 〈eta,γa〉a( f :∀X p.(Self : D 〈X i〉)⇒σ) ∈Γ Γ, Xk |Θ∗,pi j 〈x j , c j〉 ` fun : [ f :σ′] | ; f :σ′t = etFσ′ = [up/X p]σ Γ |Θ`WF ∀Xk.pi j ⇒ u : D 〈ui〉 σtD σtD =∀Xk.∀ω j .fn(τtj)→ SD 〈utp〉Γ |Θ` impl〈Xk〉D 〈ui〉 for uwhere pi j {type A = uA ; fun }: ; | [∀Xk.pi j ⇒ u : D 〈ui , A 7→ uA〉 〈xu:D〈ui〉, cu:D〈ui〉〉] axiom cu:D〈ui〉 :∀Xk.AD 〈utp〉 7→ utAxu:D〈ui〉 :σtD =ΛXk.Λc j :ω j .fn (x j : τtj) { SD 〈utp〉 { f : etF , xs : ets, xa : eta }};...continued in figure 7.5Figure 7.4: MiniRust: well-typed items with translation82trait dictionaries and coercions that correspond to the constraints pi j.7.6.1 Translating traitsRule (trait) is used to type non-object-safe trait declarations and it provides their transla-tions. The translation of a trait consists of multiple RustIn items. One of the resulting itemsis a struct declaration that defines the type of the trait’s dictionary. The struct’s fields in-clude the trait function f , the dictionaries of the trait’s supertraits xs and the dictionaries ofthe trait’s associated type constraints xa. Since supertrait and associated type constraintsof a trait D are propagated, a satisfied constraint on D lets us infer that D’s supertrait andassociated type constraints are also satisfied. The fields xs and xa in D’s dictionary are usedas evidence of that. The RustIn functions xD,s and xD,a correspond to the propagated con-straint schemes. They take as input a dictionary of D and they output their correspondingpropagated dictionaries obtained from the input dictionary.The translation of the declaration of a trait D also contains a top-level function f cor-responding to D’s trait function. It is a higher-order function that simply takes as input adictionary of D and applies the concrete version of the trait function that is in the dictionary.The associated type declared in the trait is translated to a corresponding abstract typedeclaration. Since the associated type instantiations in supertrait and associated type boundsare also propagated, they are translated to type equality axioms that declare the coercionconstants cD,a and cD,s.7.6.2 Translating implsThe translation of an impl declaration in rule (impl) consists of two RustIn items that cor-respond to the rule’s output constraint scheme. The first item is an axiom that declares theabstract type instantiation corresponding to the instantiation of the trait’s associated type inthe impl’s body. The second item is a generic function that produces an instance of the structdeclared by the implemented trait, representing the trait dictionary. If the impl is universallyquantified by some variables Xk in its header, then its dictionary is also universally quanti-fied by the type variables Xk. Similarly, if the impl is qualified by some constraints pi j in itswhere-clause, then the dictionary is accordingly abstracted over coercions and dictionariesthat represent those constraints. The supertrait and associated type constraint dictionariesets and eta are obtained in the rule’s side conditions that verify that that those constraints aresatisfied by the impl.83Γ |Θ` item :Γ |Θ pgmt (Well-typed items)(obj-trt){pi j}≡ {(SelfU :βs),pih} X p = SelfU, X i Γ |Θ`WF ∀X p.SelfU : D 〈X i〉⇒pih _hτ= fn(&SelfU,τm)→ τR σ′ =∀X p.(Self : D 〈X i〉)⇒ τ Γ |Θ`WF σ′ σ′tΓ, X p |Θ,SelfU : D 〈X i〉 `WF τ σtΓ |Θ`WF ∀X p.(SelfU : D 〈X i〉)⇒ SelfU :βs 〈∀X p.fn(SD 〈X p〉)→ τts,ϑs〉sΓ |Θ`WF ∀X p.(SelfU : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈∀X p.fn(SD 〈X p〉)→ τta,ϑa〉aΓ, X p `D 〈X i〉 ⇑{Dd 〈ud nn, Ad 7→?〉d}Ad :: Xduobj =∃T : D 〈X i, AD d 〈T, [T/SelfU]ud nn〉 ∼ Xdd〉pid = uobj : Dd 〈[uobj/SelfU]ud nn, Ad 7→ Xd〉dΓ, X i, Xd |Θ | ∀X i, Xd .pid 〈xd , cd〉 `os pid 〈etd ,pid m xd m〉dΓ |Θ`WF ∀X i, Xd .pid mm ⇒pid 〈∀X i, Xd .∀ωd m.fn(τtd m)→ τtd , ∀X i.Xd .utd ∼∀X i.Xd .Xd〉dΓ |Θ`trait D 〈X i〉 for SelfUwhere pi j {type A :βa;f : τ; }:[(D 〈X i〉where pih, SelfU :βs xs, A :βa xa, f ,obj-safe),f :σ′] |[∀X p.(SelfU : D 〈X i〉)⇒ SelfU :βs 〈xD,s, cD,s〉s,∀X p.(SelfU : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈xD,a, cD,a〉a,∀X i, Xd .pid mm ⇒pid 〈xd , cd〉d] type AD 〈X p〉 ; axiom cD,a :ϑaa; axiom cD,s :ϑss; struct SD 〈X p〉 { f :σt, xs : τts, xa : τta}f :σ′t =ΛX p.fn (xD : SD 〈X p〉){ xD . f };xD,s :∀X p.fn(SD 〈X p〉)→ τts =ΛX p.fn (xD : SD 〈X p〉){xD .xs};sxD,a :∀X p.fn(SD 〈X p〉)→ τta =ΛX p.fn (xD : SD 〈X p〉){xD .xa};axd :∀X i, Xd .∀ωd m.fn(τtd m)→ τtd =ΛX i, Xd .Λcd m :ωd m.fn (xd m : τtd m) {etd};daxiom cd :∀X i, Xd .utd 7→ Xd ;d(D 〈X i〉 where _,SelfU : Ds 〈uns, As 7→ _〉 _, A : _,_,_) ∈Γ Γ`Ds 〈[ui/X i]uns〉 ⇑ {β j s}sΓ`D 〈ui〉 ⇑{β j s, D 〈ui, A 7→?〉}Figure 7.5: MiniRust: well-typed object-safe traits with translation84Γ |Θ |Θ`piVpi γΓ |Θ1,Θ2 u1 ∼ u2 γ1 Γ |Θ1,Θ2 u1 i ∼ u2 i γiiΓ |Θ1 `WF u2 : D 〈u2 i, A 7→?〉Γ |Θ1 |Θ2 ` u1 : D 〈u1 i, A 7→?〉V u2 : D 〈u2 i, A 7→?〉 SD 〈γ1,γi〉Γ |Θ1,Θ2 u1 ∼ u2 γ1 Γ |Θ1,Θ2 u1 i ∼ u2 i γiiΓ |Θ1,Θ2 u3 ∼ u4 Γ |Θ1 `WF u2 : D 〈u2 i, A 7→ u2〉Γ |Θ1 |Θ2 ` u1 : D 〈u1 i, A 7→ u3〉V u2 : D 〈u2 i, A 7→ u4〉 SD 〈γ1,γi〉Γ`pi 7→β et(path1)(D1 〈X i〉 where _,SelfU :βs xs,_,, _)(D3 〈uk, A 7→ _〉 x) ∈{[u/SelfU][ui/X i]βs xs}Γ` u : D3 〈uk〉 7→D2 〈u j〉 etΓ` u : D1 〈ui〉 7→D2 〈u j〉 x.et(path2)(D1 〈X i〉 where _,_,_, f ,_)Γ` u : D1 〈ui〉 7→D1 〈ui〉 fΓ |Θ | θd 〈_, c′d〉 `os uobj : D 〈ui, A 7→ X 〉 〈etD ,pis x′s,pia x′a〉whereuobj =∃T : Dobj 〈Xh, AD d 〈T,und〉 ∼ Xd〉(D 〈X i〉 where _,SelfU :βs xs, A :βa xa, f ,obj-safe) ∈ΓΓ |Θ | θd 〈_, c′d〉 ` uobj : [uobj/SelfU][ui/X i]βsVpis γssΓ |Θ | θd 〈_, c′d〉 ` AD 〈uobj,ui〉 : [uobj/SelfU][ui/X i]βaVpia γaa( f :∀SelfU, X i.(SelfU : D 〈X i〉)⇒ fn(&SelfU,τm)→ τR) ∈ΓΓ |Θ`WF ∀SelfU, X i.(SelfU : D 〈X i〉)⇒ fn(&SelfU,τm)→ τR ∀SelfU, X i.fn(SD 〈SelfU, X i〉)⇒ fn(&SelfU,τtm)→ τtRΓ |Θ,uobj : Dobj 〈Xh〉 `WF uobj : D 〈ui〉 SD 〈utobj,uti〉(AD 〈T,u′i〉 ∼ X ) ∈ {AD d 〈T,und〉 ∼ Xd}Γ′ |Θ′ [T/SelfU][u′i/X i]τR ∼ [uobj/SelfU][ui/X i]τR γΓ′ |Θ′ [uobj/SelfU][ui/X i]τm ∼ [T/SelfU][u′i/X i]τm γmmΓ′ =Γ,TΘ′ =Θ,θd 〈_, c′d〉, T : Dobj 〈Xh〉 , T : Dd 〈und, A 7→ Xd〉 〈_, cd〉Γ,T `T : Dobj 〈Xh〉 7→D 〈u′i〉 etPetD = SD 〈utobj,uti〉{f : fn (xobj :&utobj, xm : [utobj/SelfU][uti/X i]τtm) {let (T, xval, xdict, cd)= unpack xobj inxdict.etP (xval, xmI γm)I γ},xs : x′sI sym (γs),xa : x′aI sym (γa)}Figure 7.6: MiniRust: auxiliary object-safe trait relations with translation857.6.3 Translating object-safe traitsFigure 7.5 presents the object-safe trait typing rule, (obj-trt). In addition to the RustIn itemsproduced by non-object-safe traits in rule (trait), translation of object-safe traits containsitems that correspond to the trait object constraint schemes output by the rule. The itemsinclude top-level term declarations xd and type equality axioms cd. The terms assigned to xdare polymorphic functions. They take as input the coercions and dictionaries correspondingto the supertrait and associated type constraints pid m, which we obtain using the auxiliaryrelation `os. The functions’ return values are dictionaries etd, also obtained from the relation`os, that serve as evidence that the trait’s descriptor implements the traits Dd in the descrip-tor’s supertrait hierarchy. The type equality axioms cd are translations of the associated typeinstantiations in the trait object constraint schemes.The auxiliary relation Γ |Θ | θd 〈_, c′d〉 `os uobj : D 〈ui, A 7→ X 〉 〈etD ,pis x′s,pia x′a〉is presented in figure 7.6. The relation is extended to include in its outputs the dictionary etDcorresponding to constraint uobj : D 〈ui, A 7→ X 〉. The relation also includes variable namesx′s, x′a for the dictionaries corresponding to the supertrait constraints pis and associated typeconstraints pia. The variables are used in the construction of the trait object dictionary et,since in (obj-trt)’s output, the dictionary is abstracted over them.The side conditionsΓ |Θ | θd 〈_, c′d〉 ` uobj : [uobj/SelfU][ui/X i]βsVpis γssΓ |Θ | θd 〈_, c′d〉 ` AD 〈uobj,ui〉 : [uobj/SelfU][ui/X i]βaVpia γaagive us the constraints pis and pia, which are type parameter-wise equivalent to the supertraitand associated type constraints of the trait D instantiated with types uobj,ui. The coercionsγs and γa relate the dictionaries of the constraints from the left-hand side of the arrow Vwith the dictionaries of their equivalent constraints from the right-hand side of the arrow.To construct the dictionary etD we use the coercions from the helper relation as well as thecoercions γ,γm that result from the type equality constraints on the trait function’s argumentand return types. The coercions help ensure that the the struct’s fields are well-typed.We also introduce a helper relation Γ ` pi 7→ β et, which provides a path et from thedictionary of pi to the trait function of the dictionary corresponding to the bound of β. Therelation is defined for bounds β that are in the supertrait hierarchy of the constraint pi.In the body of etD , the function f , representing D’s trait function, unpacks the trait objectxobj and applies the function contained in the dictionary xdict encapsulated in the object. Weapply the coercions γm and γ to ensure that the body of f is well-typed.The fields xs and xa in etD correspond to D’s supertrait and associated type constraint dic-86`P pgm :Γ |Θ pgmt (Well-typed programs)(pgm)Γ |Θ` itemi :Γi |Θi pgmti Γ=Γi Θ=Θi`P itemi :Γ |Θ pgmtiFigure 7.7: MiniRust: well-typed programs with translationtionaries respectively. We assign to them the term variables x′s, x′a, corresponding to trans-lations of pis,pia, coerced with sym γs and sym γa respectively to ensure that the fields’ typesmatch the definition of the struct SD .7.6.4 Translating programsThe program typing and translation rule is presented in figure 7.7. The rule is straight-forward. A well-typed program simply translates to a concatenation of the partial RustInprograms generated from its items.7.7 Type preservation of translationBefore we present the theorems of type preservation, we need to be able to reason aboutwhat constitutes a well-formed environment. The well-formed environments judgment ispresented in figure 7.8. Intuitively, in a well-formed environment, all of its members arewell-formed. A well-formed trait information tuple in a typing environment means that thetrait satisfies the side conditions as prescribed by the (trait) or (obj-trt) rule. The rules in thefigure also include translations to corresponding RustIn environments.We first show that well-typed MiniRust terms translate to well-typed RustIn terms andthe types of both terms are also related by translation.Theorem 7.1 (Translation of terms preserves well-typedness). If:• Γ |Θ` e : τ et and• Γ |Θ`WF τ τt and• 〈Γ,Θ〉 〈Ωt,Γt〉,then Ωt |Γt | ; `T et : τt.The subscript T in Ωt | Γt | ; `T et : τt signals that we are referring to a RustIn judgment(specifically the well-typed terms judgment in figure 6.4).We then show that well-typed MiniRust items translate to well-typed RustIn items:87Γ |Θ`Γ 〈Ωt,Γt〉 (Well-formed typing environments)(Γ;)Γ |Θ`; 〈;,;〉 (ΓX )Γ |Θ`Γ′ 〈Ωt,Γt〉Γ |Θ`Γ′, X 〈Ωt, (Γt, X )〉(Γvar)Γ |Θ`Γ′ 〈Ωt,Γt〉 Γ |Θ`WF σ σtΓ |Θ`Γ′, x :σ 〈Ωt, (Γt, x :σt)〉(Γsct)Γ |Θ`Γ′ 〈Ωt,Γt〉 Γ, X j |Θ`WF τi τtiΓ |Θ`Γ′,S 〈X j〉 {xi : τi} 〈(Ωt,S 〈X j〉 {xi : τti}),Γt)〉(Γtrt)Γ |Θ`Γ′ 〈Ωt1,Γt〉 X p =Self, X i Γ, X p |Θ,Self : D 〈X i〉 `WF Self :βs 〈τts,ωs〉sΓ, X p |Θ,Self : D 〈X i〉 `WF AD 〈X p〉 :βa 〈τta,ωa〉a( f :∀X p, Xk.(Self : D 〈X i〉 ,pil)⇒ τ) ∈Γ(∀X p.(Self : D 〈X i〉)⇒Self :βs _s) ∈Θ (∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa _a) ∈ΘΓ, X p |Θ,Self : D 〈X i〉 `WF ∀Xk.pil ⇒ τ σt Ωt =Ωt1, SD 〈X p〉 { f :σt, xs : τts, xa : τta}, AD 〈X p〉Γ |Θ`Γ′, (D 〈X i〉where pih,Self :βs xs, A :βa xa, f ,obj) 〈Ωt,Γt〉Γ |Θ`Θ 〈Ωt,Γt〉 (Well-formed constraint environments)(Θ;)Γ |Θ`; 〈;,;〉 (Θθ)Γ |Θ`Θ′ 〈Ωt,Γt〉 Γ |Θ`WF θ 〈σt,ϑ〉Γ |Θ`Θ′, (θ 〈x, c〉) 〈(Ωt, c :ϑ), (Γt, x :σt)〉〈Γ,Θ〉 〈Ωt,Θt〉 (Well-formed environments)(tr-envs)Γ |Θ`Γ 〈Ωt1,Γt1〉 Γ |Θ`Θ 〈Ωt2,Γt2〉Ωt =Ωt1,Ωt2 Γt =Γt1,Γt2〈Γ,Θ〉 〈Ωt,Θt〉Figure 7.8: MiniRust: well-formed environments with translationTheorem 7.2 (Translation of items preserves well-typedness). Suppose Γ′ ⊆Γ and Θ′ ⊆Θ.If Γ |Θ` item :Γ′ |Θ′ itemti and 〈Γ,Θ〉 〈Ωt,Γt〉then there are some Ωt1,Ωt2,Γt1,Γt2,Ωti,Γti such that :• Γ |Θ`Γ′ 〈Ωt1,Γt1〉,• Γ |Θ`Θ′ 〈Ωt2,Ωt2〉,• Ωt |Γt `T itemti :Ωti |Γti,• Ωti =Ωt1,Ωt2 and• Γti =Γt1,Γt2.88Finally, we show that well-typed MiniRust programs translate to well-typed RustIn pro-grams and that their resulting environments are related by the translation rules in figure7.8.Theorem 7.3 (Translation of programs preserves well-typedness). If `P pgm pgmt : Γ |Θand then there are some Ωt,Γt such that 〈Γ,Θ〉 〈Ωt,Γt〉 and `T pgmt :Ωt |Γt.Proofs of the above theorems can be found in appendix B.7.8 Discussion7.8.1 Type safety of MiniRustTo prove that well-typed MiniRust programs are type-safe, we must show that their RustIntranslations satisfy the requirements for type safety, as defined in theorem 6.3. One of thoserequirements is that the top-level items must include a function main of type fn()→ (), whichwe already enforce in MiniRust. Another requirement is that the top-level environment Ωtproduced in `T pgmt :Ωt |Γt must be consistent, as specified in definition 6.4. One necessarycondition for consistency is that source programs should not have overlapping impls. Wediscuss impl overlap and how it may affect consistency in the next chapter.7.8.2 MonomorphizationAs mentioned in chapter 2, to prevent traits and generics-based abstractions from introduc-ing runtime overhead in Rust, generic items are monomorphized at compile-time, i.e., thecompiler performs a translation pass on the program where generic items are translated totheir monomorphic versions based on types with which they are used in the program. Ourformalization of the runtime semantics of MiniRust, through a translation to an internallanguage where dictionaries corresponding to traits are passed around at runtime, is quitedifferent from the Rust compilation model. While our specification of the operational seman-tics of MiniRust programs does not reflect Rust’s runtime cost model, through evidence-basedtranslation we are able to reason more clearly about the modular qualities of traits and abouttype safety of programs with traits. In particular, the trait dictionary structure gives us aclear insight into what is required for a type to implement a trait. We conjecture, however,that trait dictionaries in RustIn programs can still be compiled away and that RustIn genericitems can be monomorphized similarly to the monomorphization process in Rust. As such,RustIn can serve as an intermediate language between MiniRust and some other monomor-phic target language.89Chapter 8CoherenceAs we discussed in the previous chapter, in languages with type-based overloading, such asRust, the operational meaning of a term may depend on its type. It is common to definethe operational semantics of such languages in terms of a type-based translation to a targetlanguage where the overloads have already been resolved, as we have done in this thesis.However, if the type system is non-deterministic, in the sense that it allows a term to havedifferent types, then such a term may produce different translations.Coherence is a property of a type system where the meaning of a term does not depend onthe way it was type-checked [10]. Therefore, in a coherent type system, a program with twodifferent typing derivations, once evaluated, should produce the same observable result. It isa desirable property, especially in a system focused on predictability.The type system of MiniRust, in the absence of restrictions, is in fact incoherent. For in-stance, an ambiguous trait function call, where the arguments provided to the trait functiondo not provide enough information to determine the trait parameter instantiations used inthe call, can result in not knowing which impl to use to resolve it. For example, consider thefollowing two traits (using Rust syntax):trait FromString {fn from_str(String) -> Self}trait ToString {fn to_str(self) -> String}Suppose that both FromString and ToString have implementations for floats f64 andintegers i32. Then, in the variable declarationlet x = to_str(from_str("5"));90we know that x has type String but there is no way to know which implementations offrom_str and to_str are to be used.Ambiguity problems like the above can be solved by simply requiring the programmer toprovide type annotations (in Rust, from_str has to be called using the explicit UFCS, since itis not a method). However, if there is ambiguity in impl matching that is due to overlappingimpl declarations, type annotations cannot solve the problem. Consider the following twoimpls of FromString:impl<T> FromString for T { ... }impl FromString for f64 { ... }The first impl is a blanket impl: it implements FromString for all types. Thus, the followingcall to from_str:let y: String = ...let x: f64 = from_str(y);is ambiguous as both implementations of from_str can be used to resolve it. Therefore,Rust includes rules that ensure trait coherence: that for every concrete instantiation of traitparameters there is at most one matching impl.In the context of the subset of Rust formalized in MiniRust, where programs do not in-clude external library dependencies, this simply means that we must not allow overlap inimpl declarations. Specifically, for any given two impls that produce constraint schemesθ1 = ∀X i.pi j ⇒ pi1 and θ2 = ∀Xk.pil ⇒ pi2 we must ensure that there is no type substitutionφ = [u/X ] that maps type variables to types such that φ(pi1) = φ(pi2) and Γ | Θ φ(pi) for allpi ∈ {pi j,pil}, where Γ and Θ are the top-level typing and constraint environments respectively.However, in the presence of library dependencies, traits and impls from external crates—Rust compilation units, which can be libraries—come into scope. If we want library writers tosafely extend their crates without introducing incoherence in their user crates, while allowingusers to implement external traits, more care must be taken to ensure trait coherence. Inthis chapter, we consider the current rules that are meant to ensure trait coherence in Rustin the presence of external crate dependencies. We extend the type system of NanoRust,presented in chapter 3, with crates and we adapt the Rust trait coherence rules to our model.We then show that the rules satisfy the guarantees that they are set to satisfy. Finally,we briefly discuss the pieces needed to extend our theorems and proofs to MiniRust and wediscuss the role of trait coherence in proving type safety of MiniRust. Note that in our formaldevelopment in this chapter we disregard supertrait constraint schemes generated by traitdeclarations. We discuss their implications on trait coherence in section 8.4.918.1 Crates and trait coherenceCrates are the compilation units in Rust. A crate is usually either a library crate or anexecutable crate that is compiled to a binary. The programmer can declare a dependency onan external crate by declaringextern crate my_lib;at the top of the program, where my_lib is the name of the crate used.To access an item of an external crate, we specify the path to the item that includes thecrate name. For example, we writelet x = my_lib::lib_function();to call the function lib_function declared in the my_lib crate.When we declare a dependency on an external crate, all traits and impls from that cratecome into scope. This means that, even though the imported crate does not contain over-lapping impls, the impls declared in that crate could overlap with impls from other cratesthat are in scope. Suppose the trait ToString is declared in the standard library crate but itdoesn’t have any impls. Then suppose that we have two library crates lib1 and lib2, bothdependent on the standard library:lib1 lib2fn lib1_function() { ... } fn lib2_function() { ... }impl ToString for i32 { ... } impl ToString for i32 { ... }If we want to use both lib1_function and lib2_function in our code, we have to importboth lib1 and lib2 and thus we would have two conflicting implementations of ToString fori32.As such, Rust enforces trait coherence rules, in the form of an overlap check and an or-phan rule. The orphan rule effectively restricts the impls that can be declared in a crate. Thegeneral idea behind the rule is that an orphan impl—an impl that implements an externaltrait—can only be implemented for some local type (a type declared in the impl’s local crate).The goal of the orphan rule, along with the overlap check, is to make sure that crate de-pendencies can be added safely, without causing impl overlap. Moreover, the trait coherencerules are designed in a way that is meant to give library writers the freedom to add non-blanket impls without breaking any downstream crates—crates that depend on the library.The trait coherence rules in Rust, including the orphan rule, are documented in [2].928.2 NanoRust with cratesWe now introduce crates to the type system of NanoRust. K ∈ CRATE ranges over cratenames. We introduce a new crate environment Π defined as follows:Π ::= Π,K : 〈{K i},Γ,Θ〉 | ;The tuple 〈{K i},Γ,Θ〉 represents the contents of a crate. Specifically, it includes a set of crateidentifiers K i that are imported by the crate, and it includes local environments Γ,Θ repre-senting the impls and typings of the items declared in the crate. The crate environment Π isthen a set of bindings of crate identifiers to their tuples.To facilitate reasoning about typing and constraint environments that span multiplecrates we will use the following metafunctions:tenv (Π,K)= tenv (Π,K i)i,Γ where Π(K)= 〈{K i},Γ,Θ〉cenv (Π,K)= cenv (Π,K i)i,Θ where Π(K)= 〈{K i},Γ,Θ〉ltenv (Π,K)=Γ where Π(K)= 〈{K i},Γ,Θ〉lcenv (Π,K)=Θ where Π(K)= 〈{K i},Γ,Θ〉The functions tenv (Π,K) and cenv (Π,K) respectively output the typing and constraintenvironments that are in scope in crate K , including the environments of K ’s ancestor crates.The functions ltenv (Π,K) and lcenv (Π,K), on the other hand, respectively output the typingand constraint environments local to the trait K—environments that describe items declareddirectly in the crate K .Note that the metafunctions tenv (Π,K) and cenv (Π,K) are recursive. To ensure thatthey are well-founded or terminating, we restrict Π to not have any circular crate dependen-cies. We will maintain this restriction on crate environments throughout this chapter.To help us reason about crate dependencies, we introduce a crate dependency relationΠ` K1 v K2, which we read as “crate K1 is dependent on crate K2 under crate environmentΠ”. We define the relation formally as follows:(K1 : 〈{K ,K2},Γ,Θ〉) ∈ΠΠ`K1 vK2K ∈ dom(Π)Π`K vKΠ`K1 vK3 Π`K3 vK2Π`K1 vK2The restriction on circular crate dependencies can then be stated formally as follows: “ifΠ`K1 vK2 and Π`K2 vK1 then K1 =K2”.We can extend the syntax of programs in NanoRust to include crate importing statements:pgm ::= extern K ; item93S 〈_〉 {x : τ} ∈ΓΓ` S(D 〈_〉where _,_,_) ∈ΓΓ`DFigure 8.1: Helper relationsA program, which is also a crate, then consists of extern statements, which declare dependen-cies on some external crates K , and a collection of items. To reflect the change in the programsyntax, we adapt the NanoRust program typing relation ` pgm : Γ |Θ to use the crate envi-ronment Π. We can read the new relation, Π ` K .pgm : Π′, as “under crate environmentΠ, the crate K corresponding to program pgm produces a crate environment Π′”. We use asingle rule to define the relation:(pgm)Γ |Θ` itemi :Γi |Θi i Γ= tenv (Π,K j) j,Γi Θ= cenv (Π,K j) j,ΘiΠ`K .extern K j; itemi : [K : 〈{K j},Γi,Θi〉]The rule is similar to the original NanoRust program typing rule in figure 3.4. The typingand constraint environments Γ,Θ, used in the item typing premises, include the environ-ments from the imported crates K j. The output of the (pgm) rule is a binding of the currentcrate identifier K to its tuple, which contains the identifiers of the imported crates and thelocal environments corresponding to the items in K .Our extension to NanoRust does not include paths that qualify references to items fromexternal crates (e.g. crate_name::function()). We simply assume that all items in all cratesin Π have unique identifiers.8.3 Trait coherence in NanoRust with cratesThe mechanism that ensures trait coherence in Rust consists of two parts: the orphan ruleand the overlap check. Roughly speaking, the orphan rule ensures that an impl doesn’timplement a non-local trait for a non-local type.We first define a local type as a type of a struct declared in the local crate or a referenceto a local type. We present the definition in the relation Π`LT K.τ, which we read as “undercrate environment Π, the type τ is local to crate K”. The relation is defined as follows:(l-struct)ltenv (Π,K)` SΠ`LT K .S 〈τi〉(l-ref)Π`LT K .τΠ`LT K .&τThe rule (l-struct) uses in its premise the helper relation Γ ` S, defined in figure 8.1, whichproves that the struct S is in scope of the typing environment Γ.We can now state the orphan rule for NanoRust with crates:94Definition 8.1 (Orphan rule). Under crate environment Π, a constraint τ0 : D 〈τ1, . . . ,τn〉obeys the orphan rule with respect to crate K if either:• trait D is local to crate K, or• there is a type τL in [τ0,τ1, . . . ,τn] such thatΠ`LT K.τL and, for all types τi that precedeτL in the above sequence, FV (τi)=;.We can restate the above definition as a relation Π`OR K .pi defined below:(orph1)ltenv (Π,K)`DΠ`OR K .τ : D 〈τi〉(orph2)Π`LT K .τΠ`OR K .τ : D 〈τi〉(orph3)Π`LT K .τ FV (τ0,τi)=;Π`OR K .τ0 : D 〈τi,τ,τ j〉The side condition in rule (orph1) uses a helper relation, defined in figure 8.1, that ensuresthat the trait D is in scope of the local typing environment of crate K .We say that a constraint scheme ∀Ti.pii ⇒ pi obeys the orphan rule with respect to somecrate K if and only if its end constraint pi obeys the orphan rule with respect to K . It is alsoworth noting that we are not keeping track of free type variables in scope—we simply don’tneed to.The other component of the trait coherence system in Rust is the overlap check, whichensures that two impls don’t overlap. In Rust, whenever an impl is declared in some crateK , the overlap check verifies that the impl doesn’t overlap with any other impls that are inscope. When checking for overlap, if there is a trait parameter instantiation that unifies thetwo impls, we must verify the constraints in both impls’ where-clauses to ensure that at leastone of them is not satisfied. The constraint satisfaction check used to do so is strictly morepermissive than the one used for resolving trait method calls (whose corresponding constraintentailment relation in NanoRust is presented in figure 3.2). In particular, we assume thatconstraints that do not satisfy the orphan rule for the current crate are satisfied, because thecrate in which the constraint satisfies the orphan rule, could add a corresponding impl in thefuture. Similarly, blanket constraints—which are, roughly speaking, trait constraints whereat least one trait parameter is a type variable—are considered satisfied as well. Consider thefollowing pair of impls:impl<T> MyTrait for T where T: Foo { ... }impl<T> MyTrait for T where T: Bar { ... }To conclude that the above two impls don’t overlap, we would have to prove that the traitsFoo and Bar are mutually exclusive—that there is no type τ such that both τ : Foo and τ : Barare satisfied. There is no way to guarantee that no external crate will implement both Fooand Bar for the same type, so the above two impls are considered overlapping.95We formalize constraint satisfaction in the context of an overlap check in a new crate-aware constraint entailment relation. Before we present the new constraint entailment rules,we introduce a new syntactic set B ∈BLANKETTYPE defined as follows:B ::=T |&BA blanket type is thus a type variable or a reference to a blanket type. We then define thenew crate-aware constraint entailment relation Π |ΘK .pi below:(cons)∀Ti.pi j ⇒pi ∈Θ Π |ΘK . [τi/Ti]pi jjΠ |ΘK . [τi/Ti]pi(blanket1)Π |ΘK .B : D 〈τ〉(blanket2)Π |ΘK .τ : D 〈τi,B,τ j〉(orphan)Π 6`OR K .piΠ |ΘK .piThe relation is parameterized by the local crate K . In rule (orphan), 6`OR denotes thecomplement of `OR. Note that the set of constraints entailed in this relation, with respect tosome constraint environment Θ, is a strict superset of the set of constraints entailed in theNanoRust constraint entailment relation from figure 3.2:Theorem 8.1. If Γ |Θpi then Π |ΘK .pi for any crate environment Π and crate K.Proof. Straightforward induction on derivations Γ |Θpi.We can now formally state the definition of non-overlapping impls:Definition 8.2 (Non-overlapping impls).Given two impls with corresponding constraint schemes:θ1 =∀Ti.pi j ⇒pi1 ∈ lcenv (Π,K1) andθ2 =∀Tk.pil ⇒pi2 ∈ lcenv (Π,K2),we say that θ1 and θ2 don’t overlap under Π,Θ iff for each type substitution φ= [τ/T] such thatφ(pi1)=φ(pi2), there is a constraint pi ∈ {pi j,pil} such that Π |Θ1K .φ(pi) whereK =K1 if Π`K1 vK2K2 if Π`K2 vK1any K ∈ dom(Π) otherwiseand 1 is the complement of .The above definition of non-overlapping impls aims to capture what the overlap checkin Rust is doing. Of particular note is that the overlap check in Rust only considers pairsof impls declared in crates that are related to one another: the overlap check compares animpl in crate K with impls that are in crates that K depends on. Our definition, however,also lets us reason about impls declared in unrelated crates (crates that do not depend on96one another). In such cases, there is no clear ‘local’ crate K to consider when invoking theconstraint entailment relation Π | Θ K .pi. It turns out, as we will show in the proofof theorem 8.2, that we do not need to decide which K to use as if impls represented by∀Ti.pi j ⇒ pi1 and ∀Tk.pil ⇒ pi2 come from unrelated crates then there is no substitution φsuch that φ(pi1)=φ(pi2).Finally, we define a consistent crate below.Definition 8.3 (Consistent crates). Suppose (K : 〈{K i},ΓK ,ΘK 〉) ∈Π.Let Θ= cenv (Π,K) and Γ= tenv (Π,K). Crate K is consistent in the crate environment Π iff1. each crate K ′ ∈K i is consistent in Π,2. 〈Γ,Θ〉 are well-formed,3. every impl in ΘK obeys the orphan rule with respect to crate K,i.e., if (∀T.pi⇒pi) ∈ΘK then Π`OR K .pi, and4. for all pairs of impl constraint schemes in Θ, there is no overlap under Π,Θ according todefinition 8.2.By saying that 〈Γ,Θ〉 are well-formed, we mean that each member of the environmentsis well-formed with respect to Γ (similarly to the well-formed environments judgment inMiniRust presented in chapter 7). An important insight from the above definition is thatthere are no overlapping impls in the scope of a consistent crate.One purpose of the trait coherence rules is to ensure that importing one or more cratewill not cause overlapping impls. The following theorem formalizes that guarantee:Theorem 8.2 (Trait coherence). Suppose:• (K : 〈{Kr},ΓK ,ΘK 〉) ∈Π,• each crate K ′ ∈Kr is consistent in Π,• 〈tenv (Π,K),cenv (Π,K)〉 well-formed,• every impl in ΘK obeys the orphan rule w.r.t. crate K, and• for every pair of impl constraints schemes θ1 ∈ΘK and θ2 ∈ cenv (Π,K),θ1 and θ2 don’t overlap under Π and cenv (Π,K).Then K is consistent in Π.97The above theorem tells us that, given a crate K that depends on crates Kr, if each crate inKr is consistent and if the impls in K don’t overlap with any impls in Kr, then K is consistent.Specifically, the theorem guarantees that linking to consistent crates from a consistent cratemaintains trait coherence.Another purpose of the trait coherence rules is to give some flexibility for library crates toadd impls without introducing overlap in their user crates. The only additional restriction onthe new impls (in addition to not causing overlap in the scope of K and satisfying the orphanrule) is that they cannot be blanket impls, that is, none of their trait parameter instantiationscan be blanket types. The following theorem states that guarantee formally:Theorem 8.3 (Crate extensibility). Let K be a consistent crate under Π whereΠ = Π′′∪ {K : 〈{Ka},ΓK ,ΘK 〉}. Then let Π′ = [K ′/K]Π′′∪ {K ′ : 〈{Ka},ΓK ,ΘK ∪ {θ1}〉} where K ′ isconsistent in Π′ and θ1 = ∀Tk.pi j ⇒ τ1 : D 〈τ1n〉 with τ 6∈ BLANKETTYPE for each τ ∈ {τ1,τ1n}.Then, for each crate K1 such that Π′ ` K1 v K ′, if K1 is consistent under Π, then it is alsoconsistent under Π′.The proofs of both of the above theorems can be found in the appendix.8.4 Coherence and type safety of MiniRustOur development of the trait coherence system in this chapter is based on a fairly simple typesystem. In particular, the system does not include associated types, trait objects or propa-gated trait constraints (supertrait constraints and associated type constraints). To ensurethat the properties proven in this chapter hold in MiniRust, the work should be extended toaccount for those additional features. In this section we present a brief discussion of whatsuch extensions might entail.Associated typesOne way to handle associated types in an impl header is to treat them as type variables. Anassociated type, whose type parameters do not provide sufficient information so that it canbe matched to a specific impl, could potentially be normalized to any type, local or otherwise.That is also the approach taken in the current Rust implementation. However, one couldconsider ways to relax the coherence rules in relation to associated types. For instance, itwould seem reasonable to allow the following two impls to coexist:impl<T> IteratorWrapper for T where T: Iterator<Item = i32> { ... }impl<T> IteratorWrapper for T where T: Iterator<Item = char> { ... }The current coherence rules do not allow these impls to coexist as they are both constrainedby blanket impls, so they are deemed to overlap. However, as long as Iterator does not98have overlapping impls, then there is no type τ such that both τ : Iterator<Item = i32> andτ : Iterator<Item = char> are true.Also, the formalization would need to account for type equalities introduced in MicroRust.For example, in determining whether two constraints pi1,pi2 are unifiable, i.e., that thereexists a substitution φ such that φ(pi1) = φ(pi2), we would rather have to use type equalityof the two constraints. Concretely, we would state that the two constraints pi1 and pi2 areunifiable if and only if there is some substitution φ such that φ(pi1) is type parameter-wiseequivalent to φ(pi2).Trait objectsAdding support for trait objects should be relatively straightforward. A trait descriptor∃T.D 〈u,u1 j ∼ u2 j〉 would simply be considered a local type in the crate in which the traitD is declared (as is the case in Rust [2]). The trait object constraint schemes generated bythe object-safe trait declarations should also be included in the overlap check to ensure thatthe programmer doesn’t implement an object-safe trait for its trait descriptor type manually.Coherence in MiniRustSo far, in our presentation in this chapter, we have assumed that the top-level environment Θonly contains constraint schemes generated by impl declarations. We have effectively ignoredpropagated constraint schemes—which represent supertrait constraints and associated typeconstraints—generated by trait declarations. Clearly, if we take such constraints into con-sideration, we get overlapping constraints. For example, consider the following traits andimpls:trait Eq { ... }trait Ord: Eq { ... }impl Eq for i32 { ... }impl Ord for i32 { ... }We have two traits: Eq and Ord, where Eq is a supertrait of Ord. We also have implementationsof both traits for the type i32. Typing the above items in NanoRust would populate theconstraint environment Θ with the following constraint schemes:• ∀T.T : Ord⇒T : Eq from the trait declaration of Ord,• i32 : Eq from the impl of Eq for i32, and• i32 : Ord from the impl of Ord for i32.99It is clear that the constraint scheme ∀T.T : Ord⇒ T : Eq overlaps with i32 : Eq when T isinstantiated with i32. When we consider the dictionary translation of those constraints toRustIn, we realize that the supertrait constraint scheme ∀T.T : Ord⇒ T : Eq is a function thattakes a dictionary of Ord and returns the dictionary of Eq contained within. The dictionary ofEq is however the same as the dictionary corresponding to the constraint i32 : Eq. Therefore,even though there are two ways to solve the constraint i32 : Eq, both ways result in the sameruntime semantics.Thus, to prove trait coherence in MiniRust in the presence of supertrait and associatedtype constraints, we would have to show that different translations of any given constraintpi produce the same result at runtime. In general, to prove type system coherence, we wouldprove that all possible translations of a well-typed MiniRust term e to RustIn produce thesame result at runtime. Note, however, that in the presence of coercions, it is not sufficientto show that both translations evaluate to the same value. For example, given a constrainttranslation environment Θ that contains the entry i32 : MyTrait〈A 7→ bool〉 〈x, c〉, even avery simple term like true can be translated to true or trueI sym c ◦ c. The only differencebetween the two resulting terms is the coercion sym c ◦ c in the second term, however, as weestablished in the presentation of RustIn in chapter 6, coercions do not have any computationassociated with them. Therefore, to assess equivalence of runtime semantics of two terms,we would have to ‘erase’ coercions from their resulting values.Type safety of MiniRustRecall that the proof of type safety of RustIn in chapter 6 relies on the consistency of top-leveltype equality axioms—meaning that no nonsensical type equalities such as i32∼ bool can bederived from them. We believe that ensuring trait coherence in a MiniRust program would besufficient to conclude that the equality axioms, resulting from the translation of the program,are used consistently in the resulting RustIn program, i.e., even if the axioms are inconsistentby themselves, their corresponding coercion constants are only instantiated in a way thatdoes not introduce inconsistency (so we would never actually use an equality like i32∼ boolin the program). We motivate our intuition by the fact that associated type instantiations,which are the source of RustIn type equality axioms, come from impl declarations, which wecan prove beforehand to be non-overlapping. To complete the proof of type safety of MiniRustwe would need to prove that claim.For instance, consider the two non-overlapping impls below:impl Foo for bool { type A = char; }impl<T> Foo for T where MyStruct<T>: Bar { type A = i32; }100Their translation produces the following type equality axioms in RustIn:axiom c1 : A 〈bool〉 7→ char;axiom c2 :∀T.A 〈T〉 7→ i32;we would need to show that, in the RustIn program, the coercion constant c2 is never instan-tiated with bool and that this is sufficient to maintain type safety in RustIn. We leave suchdevelopment for future work.101Chapter 9Limitations & future workIn this chapter we discuss limitations of the work presented in this thesis and possible futurework.9.1 Limitations9.1.1 Trait featuresAs discussed in sections 3.2.1 and 4.1.1, each MiniRust trait has exactly one trait functionand one associated type, while Rust allows an arbitrary number of trait methods and associ-ated types. We also do not allow trait constraints to include instantiations of supertrait asso-ciated types (as mentioned in section 4.1.2). As discussed in section 5.1.2, in a MiniRust traitparameterized by SelfU, a trait function cannot constrain its Self type variable to be an s-type(or Sized). Compared to Rust, this restricts the set of traits that MiniRust accepts as object-safe. In fact, Rust allows object-safe traits to include methods whose receiver is self (and nota pointer to self). Such methods are implicitly qualified by the constraint Self: Sized andthey cannot be called on trait types, since trait types (descriptors in MiniRust) are dynami-cally sized and don’t satisfy the constraint (the constraint Self: Sized may also be explicitlyadded by the programmer to a trait method).9.1.2 Type safetyThere is more work to be done to fully ensure type safety of MiniRust. Specifically, we need toshow that well-typed MiniRust programs translate to RustIn programs that have consistenttop-level type equality axioms, as we discussed in section 8.4. Moreover, our type safetyproof relies on a translation to a hypothetical internal language, where trait constraints aretranslated to dictionaries, while in the Rust compilation model, trait constraints are compiledaway through monomorphization. We believe that MiniRust programs translated to RustIn102can still be monomorphized while maintaining their runtime semantics, as the dictionariescan be optimized away [21]. As future work we would formally verify this claim.9.1.3 Constraint entailmentFurthermore, constraints are resolved differently in Rust than in MiniRust. For instance,given an impl:impl<T> MyTrait for T where T: MyTrait { ... }if we try to solve the constraint i32: MyTrait in MiniRust, we would end up with an infinitederivation tree and type-checking would not terminate. On the other hand, Rust accepts thisconstraint (and any other constraint T: MyTrait for any type T) because the compiler can de-termine that the constraint i32: MyTrait is “self-supporting”. A coinductive definition of theconstraint entailment judgment would permit such cyclic derivation trees, which can provesatisfaction of the constraint. As future work we can explore the implications of resolvingconstraints coinductively on the semantics of MiniRust and on the metatheory presented inthis thesis.9.2 Towards an implementation of MiniRustThe type system of MiniRust presented in this thesis is a formal declaration of what consti-tutes a well-typed term or program. As we’ve discussed in the preceding chapter, it may allowmultiple ways to type a program: there may be more than one valid type for a given term andthere may be multiple typing derivations for a particular type assignment. The typing rulesalso involve a fair amount of guesswork, where types and type parameter instantiations haveto be ‘guessed’ at certain points.To implement the type system, we need an algorithm that provides a decidable and com-plete procedure for typing MiniRust programs. Such an algorithmic specification of the typesystem must be able to infer the correct types in the case of missing type annotations. Forinstance, we might adapt the type inference algorithm developed by Jones [20], which ex-tends Algorithm W—a unification-based type inference procedure for the Hindley-Milner typesystem [14]—with predicates. To infer types of terms, the algorithm generates and solvestype equality constraints involving new type variables that stand in for unknown types.Chakravarty et al. [12] extend the algorithm to incorporate type equality constraints arisingfrom associated type synonyms in Haskell. Additionally, we can incorporate bidirectionaltype-checking to make use of the type annotations in programs and combine type-checkingwith inference [30]. In bidirectional type systems, typing rules are stratified into checkingand synthesizing rules: checking rules verify that a term can be given a particular type and103synthesizing rules infer the type of a term. As such they provide a direction that a type-checker can take in typing a program. Bidirectional type systems have also been shown to beeasy to implement and provide better error messages than purely synthesis-based algorithms[26].An algorithmic specification of the type system should ideally be sound with respect to thedeclarative system, meaning that the type assignments determined by the algorithm shouldalso correspond to valid typings in the declarative type system. Another desirable propertyof a type-checking or inference algorithm is its completeness with respect to the type system,meaning that if a term has a valid type under the type system, then the algorithm infersit. However, this property is more difficult to achieve in cases where the type system allowsdifferent types for a term. If the type system is coherent, it might be possible to set somerestrictions on source programs (e.g. require type annotations on certain terms), for which acomplete type-checking algorithm would be possible.1A sound, complete and decidable algorithm can thus be used to implement the type sys-tem. A major advantage of an implementation is that, while the type system of MiniRust andthe related formalization presented in this thesis help us reason about well-typed programs,an implementation of the type system enables us to empirically investigate whether the typesystem accepts the programs that the language designers intended to accept.9.3 Possible extensionsThere are a number of extensions that we can include in MiniRust to bring it closer to theactual Rust language.More trait featuresOur presentation of traits does not cover the entire feature set of Rust traits. In particular,we do not model default trait methods and associated constants.A default trait method provides an implementation of a trait method inside a trait decla-ration. Impls of the trait can use that default implementation unless they explicitly overrideit. To add support for default methods to our formalization, we can simply copy the defaultmethod’s implementation from the trait declaration to an impl that does not override it.Associated constants should be straightforward to include as well: they would simply in-volve including a typed variable declaration in the trait declaration, which would be assignedto some value in an impl.1Completeness of a type inference algorithm may also mean that the algorithm infers a principal type for eachterm: a type that generalizes all possible types that a term can be given under the declaration of the type system[14, 20].104LifetimesThe subset of Rust examined in this thesis does not include any of the type system featuresthat help ensure memory safety. For instance, we do not have mutability qualifiers for vari-ables and references, and we do not adapt the ownership model. Our model also does notinclude lifetimes, based on research in region-based memory-management [19, 39]. Lifetimesare of particular interest in the study of traits because in Rust, traits and impls can also beparameterized by lifetimes.In Rust, every piece of data on the stack has a lifetime. Also, the type of a reference to avalue is parameterized by that value’s lifetime. Consider the following expression:y = &x;Suppose that x has lifetime 'a and y has lifetime 'b. For y to be well-typed, the lifetime'b must be at least as long as 'a. If x is an i32, then the type of y is parameterized by itslifetime: &'a i32.In Rust, all items that can be generic—parameterized over types—can also be parame-terized over lifetimes. For example, the following struct is parameterized by the lifetime 'aof its enclosed reference:struct IntPointer<'a> {x: &'a i32}We can then have impls parameterized by lifetimes:impl<'a> Eq for IntPointer<'a> {fn eq(&self, &IntPointer<'a>) { ... }}To add lifetimes to MiniRust, we can extend the meta-variable X , which ranges over typevariables, to also range over lifetime variables R, as done in the work on Cyclone [19]. Inthat sense, lifetimes are treated similarly to types. Rust also includes lifetime bounds inwhere-clauses. They take the form 'a: 'b, which we can read as “the lifetime 'a is at leastas long as the lifetime 'b”. This gives rise to a subtyping relation on types. For example, if'a outlives 'b then we can say that &'a i32 is a subtype of &'b i32.We expect interesting questions to arise from the formalization of the lifetime system, es-pecially with regards to associated types, trait objects and higher-rank trait bounds [3]—traitbounds universally quantified over lifetimes. Moreover, we can explore how our developmentof traits can be combined with other existing work on the Rust type system focusing on thememory safety features [31].105ClosuresA closure in Rust is an anonymous function that captures variables from its surroundingenvironment. Closures are implemented in the Rust compiler as structs that contain thevariables from the enclosing scope. Each such closure implements one or more traits from theFn family of traits: Fn, FnMut or FnOnce, depending on whether a closure has mutable accessto its environment and if it can be called more than once. Each closure has a singleton type:a type that classifies only a single term. The name of the type of a closure is not available tothe programmer—the only thing we know about such a type is that it implements some Fn*trait(s). As such, generics and traits are a fundamental part of programming with closures.Consider the following example:fn apply<T, F>(x: T, f: F) -> Twhere F: Fn(T) -> T {f(x)}In the above example, F is a type variable representing the type of the closure F. The traitbound Fn(T) -> T tells us that the closure takes a value of type T and returns a value oftype T. In the body of the function, the call f(x) is actually syntactic sugar for a trait methodcall, f.call(x). Explicitly named functions, which we have seen throughout the thesis, alsoimplement the Fn trait and can be used in place of closures in a generic function.As closures are implemented using traits, they can also take advantage of dynamic dis-patch through trait objects. In particular, trait objects allow functions to return closures:fn add_closure(x: i32) -> Box<Fn(i32) -> i32> {Box::new(move |y| x + y)}In the above example, the function add_closure takes an argument x and returns a closurethat takes an argument y and returns the sum of x and y. The return value of add_closureis a trait object (Box is a heap pointer in Rust and can also be used to create trait objects,whose enclosed values are stored on the heap). The keyword move in the body of the functionstates that the closure |y| x + y moves the variables from its surrounding environment intothe closure, instead of borrowing them (capturing the surrounding variables by reference).9.4 Rust language extensionsRust is a language under constant development. The designers of the language are continu-ously looking to improve the language and to add new features that can increase expressive-ness.106For instance, a proposed feature related to traits is impl specialization [4]. Impl special-ization would allow users to declare overlapping impls, as long as one impl is more specificthan another, given some definition of a ‘more specific than’ relation on constraints. Imple-menting such a feature in MiniRust would require a significant change to the constraint en-tailment relation: in the rules that define the constraint entailment relation we would needto reason about constraints that are not entailed. For example, to show that a constraint pi issatisfied by an impl A, we must prove that there is no impl B that also satisfies pi and is morespecific than A. This means that, to prove that A satisfies pi, we must enumerate all ways tosatisfy pi. In consequence, while defining the constraint entailment relation, we would needto reason about all the members of that same relation that we are defining. Unfortunately,such a relation is not well-defined. One way to resolve this could be to use iterated inductivedefinitions [23], which let us stratify the constraint entailment relation into multiple levelscorresponding to the level of specialization of the impl used to resolve the constraint. Thisway, in the definition of a relation at level n, we only need to know about members of relationsat levels m where m< n.107Chapter 10Related workThere has already been work on formalizing a subset of the type system of Rust’s type systemfocusing on the features that ensure memory safety, such as lifetimes, and the ownershipand borrowing system [31]. The formalization, however, does not include traits. It would beinteresting to combine the two models, particularly to examine the relationship between thememory safety-related features and traits.The term trait has generally been used in object-oriented programming languages suchas Smalltalk [32] and Scala [25]. In those cases, a trait is a composable unit of behavior thatprovides and requires functionality for/from classes that implement the trait. Rust traits aresimilar in nature, however, they are not associated with objects or classes and they can beimplemented for any type. As such, Rust traits are more closely related to type classes inHaskell [40].The formal presentation of Rust’s type system in this thesis is also based on work onHaskell, particularly on the qualified types framework developed by Jones [20]. In [24],Odersky et al. provide another framework for Hindley-Milner type systems with constraints,called HM(X), along with a type inference algorithm. Stuckey and Sulzmann [37] combineHM(X) with constraint-handling rules [17] to provide a formal basis for type systems withad-hoc polymorphism (or overloading).Associated types in Rust are also similar to associated type synonyms in Haskell, firstproposed by Chakravarty et al. in [12]. Both represent type-level functions and introduce anotion of type equality to their respective language. In one notable difference, Haskell func-tions can be constrained by equality constraints, while such constraints have to be expressedin extended trait bounds in Rust. Rust associated types are often viewed as output param-eters of a trait and in that sense they bear similarities to Haskell’s functional dependencies[22], which let the programmer declare dependency relationships between parameters of atype class.In our formalization, we also follow the Haskell implementation model for type classes.108In particular, we use the dictionary-passing style for translating trait constraints. Our trans-lation of associated types and equality constraints also mirrors the Haskell implementation,based on System FC [38, 41]. This is in contrast with the Rust language implementationwhere all type schemes are monomorphised. However, work by Jones [21] illustrates howtype class constraint dictionaries in the internal language can be optimized away, thus re-moving the runtime overhead due to passing dictionaries around.C++ templates bear some similarities to Rust generics. In particular, Rust’s way ofmonomorphizing generics is inspired by the C++ implementation of templates, which are alsomonomorphised. Unlike Rust generic functions, C++ function templates are not type-checkedbefore they are used—only the result of their instantiation is type-checked. Also, templatesrely on documentation and special encodings [1] to be constrained. There have been propos-als to include concepts in C++ [18], which would serve as a type system for templates andprovide better error messages, bringing them closer to Rust’s trait system.The Swift programming language [9] features protocols, which are also somewhat similarto traits. A protocol specifies an interface for user-defined types (structs) and classes. Theinterface can be implemented directly in the definition of the struct or class, or in an exten-sion, which then acts similarly to a Rust impl. Protocols can be used to constrain generictype variables, and they can be used as types, similarly to existential types and Rust’s traitobjects.To ensure coherence and decidability of type inference, Haskell imposes more restrictionsthan Rust on its type class instance declarations. However, the Haskell standard does notprevent declaring orphan instances, which can cause coherence errors when linking to othermodules. There has been work that proposes to let the programmer explicitly determine thescope of type class instances to ensure coherence, such as work by Dreyer et al. [15], whichattempts to unify ML modules with Haskell type classes.In [35], Siek and Lumsdaine present a new language called G, focused on generic pro-gramming. G features concepts, which are similar to Haskell type classes (and Rust traits),and models, similar to type class instances (and Rust impls). G concepts also include asso-ciated types. Models in G are lexically scoped, so two overlapping models can coexist in thesame program as long as their scopes don’t overlap. The core of the language, called FG ,which extends System F, is formalized in [34]. The work on G and FG is also featured inSiek’s PhD thesis [33].109Chapter 11ConclusionIn this thesis, we studied a subset of Rust’s type system, focusing on traits, which are thecornerstone of Rust’s abstraction mechanism. Specifically, we developed a formal language,MiniRust, which models a subset of Rust including features relevant to traits. The featuresmodeled include some advanced features of the trait mechanism such as supertraits, associ-ated types and trait objects. Through the formalization process we have discovered cornercases in the design of the language with regards to object safety of traits (the ability to cre-ate trait objects). The formal model allowed us to determine very general conditions underwhich object safety can be guaranteed. We also developed runtime semantics for MiniRustthrough type-directed translation to an internal language, RustIn, which we proved type-safe. We proved that the translation of MiniRust programs to RustIn preserves types, whichmotivates our confidence in type safety of MiniRust. We also tackled the question of traitcoherence on a subset of MiniRust, proving that the coherence rules in Rust guarantee safelinking to external libraries without breaking coherence and that they give programmers theability to safely extend their libraries without inducing impl overlap in user code.We hope that our work proves useful in shining new light on Rust and in providing abetter understanding of Rust’s trait system. In particular, our model can be a useful tool forreasoning about advanced features of traits (such as associated types and trait objects) as itabstracts away the implementation details of the language and it elides other features notcovered in this thesis, both of which increase the language’s complexity. In particular, our for-malization of trait objects and object safety can help language designers to clarify the objectsafety requirements in Rust. As such, our work can inform the design and implementationof the language. Moreover, the declarative specification of MiniRust developed in this thesiscan give rise to a corresponding type-checking algorithm. The algorithm, along with its pro-totype implementation, focusing on the core parts of the language, can serve as a referencepoint for the implementation of the Rust compiler.Our model of Rust traits can also serve as a framework for exploring additional fea-110tures, whether they are already present in the Rust (like closures and lifetimes) or they areproposed future extensions (like higher-kinded types and impl specialization). We can thusexplore how those features interact with the trait system in the context of MiniRust. More-over, the proofs presented in this thesis provide some confidence in the guarantees that Ruststrives to provide, such as type safety and trait coherence. Extending our model can thushelp us determine if those guarantees can also be satisfied in the presence of the proposedextensions.111Bibliography[1] The Boost concept check library.http://www.boost.org/doc/libs/master/libs/concept_check/concept_check.htm.Retrieved on 2015-11-29. → pages 109[2] Rebalancing coherence.https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md.Retrieved on 2015-11-23. → pages 92, 99[3] Higher-ranked trait bounds (HRTBs). https://doc.rust-lang.org/nomicon/hrtb.html.Retrieved on 2015-11-23. → pages 105[4] RFC: impl specialization. https://github.com/rust-lang/rfcs/pull/1210. Retrieved on2015-11-23. → pages 107[5] Object safety.https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md. Retrievedon 2015-11-23. → pages 47[6] The Rust programming language. http://www.rust-lang.org, . Retrieved on 2015-11-23.→ pages 2[7] The Rust programming language.http://doc.rust-lang.org/nightly/book/README.html, . Retrieved on 2015-11-23. →pages 5[8] The Servo browser engine. http://servo.org. Retrieved on 2015-11-23. → pages 2[9] The Swift programming language. https://developer.apple.com/swift/. Retrieved on2015-11-29. → pages 109[10] V. Breazu-Tannen, T. Coquand, C. A. Gunter, and A. Scedrov. Inheritance as implicitcoercion. Inf. Comput., 93(1):172–221, July 1991. ISSN 0890-5401.doi:10.1016/0890-5401(91)90055-7. URLhttp://dx.doi.org/10.1016/0890-5401(91)90055-7. → pages 90[11] K. Bruce, L. Cardelli, G. Castagna, G. T. Leavens, and B. Pierce. On binary methods.Theor. Pract. Object Syst., 1(3):221–242, Dec. 1995. ISSN 1074-3227. URLhttp://dl.acm.org/citation.cfm?id=230849.230854. → pages 47112[12] M. M. T. Chakravarty, G. Keller, and S. P. Jones. Associated type synonyms. InProceedings of the Tenth ACM SIGPLAN International Conference on FunctionalProgramming, ICFP ’05, pages 241–253, New York, NY, USA, 2005. ACM. ISBN1-59593-064-7. doi:10.1145/1086365.1086397. URLhttp://doi.acm.org/10.1145/1086365.1086397. → pages 3, 29, 103, 108[13] D. Clarke and T. Wrigstad. External uniqueness is unique enough. Technical ReportUU-CS-2002-048, Department of Information and Computing Sciences, UtrechtUniversity, 2002. → pages 2[14] L. Damas and R. Milner. Principal type-schemes for functional programs. InProceedings of the 9th ACM SIGPLAN-SIGACT Symposium on Principles ofProgramming Languages, POPL ’82, pages 207–212, New York, NY, USA, 1982. ACM.ISBN 0-89791-065-6. doi:10.1145/582153.582176. URLhttp://doi.acm.org/10.1145/582153.582176. → pages 103, 104[15] D. Dreyer, R. Harper, M. M. T. Chakravarty, and G. Keller. Modular type classes. InProceedings of the 34th Annual ACM SIGPLAN-SIGACT Symposium on Principles ofProgramming Languages, POPL ’07, pages 63–70, New York, NY, USA, 2007. ACM.ISBN 1-59593-575-4. doi:10.1145/1190216.1190229. URLhttp://doi.acm.org/10.1145/1190216.1190229. → pages 109[16] K.-F. Faxén. A static semantics for Haskell. Journal of Functional Programming, 12:295–357, 2002. ISSN 1469-7653. doi:10.1017/S0956796802004380. URLhttp://journals.cambridge.org/article_S0956796802004380. → pages 75[17] T. Frühwirth. Constraint handling rules. In Constraint programming: Basics andtrends, pages 90–107. Springer, 1995. → pages 108[18] D. Gregor, J. Järvi, J. Siek, B. Stroustrup, G. Dos Reis, and A. Lumsdaine. Concepts:Linguistic support for generic programming in C++. In Proceedings of the 21st AnnualACM SIGPLAN Conference on Object-oriented Programming Systems, Languages, andApplications, OOPSLA ’06, pages 291–310, New York, NY, USA, 2006. ACM. ISBN1-59593-348-4. doi:10.1145/1167473.1167499. URLhttp://doi.acm.org/10.1145/1167473.1167499. → pages 109[19] D. Grossman, G. Morrisett, T. Jim, M. Hicks, Y. Wang, and J. Cheney. Region-basedmemory management in Cyclone. In Proceedings of the ACM SIGPLAN 2002Conference on Programming Language Design and Implementation, PLDI ’02, pages282–293, New York, NY, USA, 2002. ACM. ISBN 1-58113-463-0.doi:10.1145/512529.512563. URL http://doi.acm.org/10.1145/512529.512563. → pages2, 65, 105[20] M. P. Jones. A theory of qualified types. In ESOP’92, pages 287–306. Springer, 1992. →pages 21, 75, 103, 104, 108[21] M. P. Jones. Dictionary-free overloading by partial evaluation. In In ACM SIGPLANWorkshop on Partial Evaluation and Semantics-Based Program Manipulation, pages107–117, 1994. → pages 103, 109113[22] M. P. Jones. Type classes with functional dependencies. In Proceedings of the 9thEuropean Symposium on Programming Languages and Systems, pages 230–244.Springer-Verlag, 2000. → pages 108[23] P. Martin-Löf. Haupstatz for the intuitionistic theory of iterated inductive definitions.In Proc. Second Scandinavian Logic Symposium, pages 179–216, 1971. → pages 107[24] M. Odersky, M. Sulzmann, and M. Wehr. Type inference with constrained types. Theor.Pract. Object Syst., 5(1):35–55, Jan. 1999. ISSN 1074-3227.doi:10.1002/(SICI)1096-9942(199901/03)5:1<35::AID-TAPO4>3.0.CO;2-4. URL http://dx.doi.org/10.1002/(SICI)1096-9942(199901/03)5:1<35::AID-TAPO4>3.0.CO;2-4. →pages 108[25] M. Odersky, P. Altherr, V. Cremet, B. Emir, S. Maneth, S. Micheloud, N. Mihaylov,M. Schinz, E. Stenman, and M. Zenger. An overview of the scala programminglanguage. Technical report, 2004. → pages 108[26] S. Peyton Jones, D. Vytiniotis, S. Weirich, and M. Shields. Practical type inference forarbitrary-rank types. J. Funct. Program., 17(1):1–82, Jan. 2007. ISSN 0956-7968.doi:10.1017/S0956796806006034. URL http://dx.doi.org/10.1017/S0956796806006034.→ pages 104[27] B. C. Pierce. Types and Programming Languages. MIT Press, Cambridge, MA, USA,2002. ISBN 0-262-16209-1. → pages 1[28] B. C. Pierce. Existential types. In Types and Programming Languages, chapter 24,pages 363–380. MIT Press, Cambridge, MA, USA, 2002. ISBN 0-262-16209-1. → pages13, 37, 41[29] B. C. Pierce. Advanced Topics in Types and Programming Languages. The MIT Press,2004. ISBN 0262162288. → pages 2[30] B. C. Pierce and D. N. Turner. Local type inference. ACM Trans. Program. Lang. Syst.,22(1):1–44, Jan. 2000. ISSN 0164-0925. doi:10.1145/345099.345100. URLhttp://doi.acm.org/10.1145/345099.345100. → pages 103[31] E. Reed. Patina: A formalization of the Rust programming language.ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf, 2015. Retrieved on2015-11-23. → pages 105, 108[32] N. Schärli, S. Ducasse, O. Nierstrasz, and A. Black. Traits: Composable units ofbehaviour. In L. Cardelli, editor, ECOOP 2003 - Object-Oriented Programming, volume2743 of Lecture Notes in Computer Science, pages 248–274. Springer Berlin Heidelberg,2003. ISBN 978-3-540-40531-3. doi:10.1007/978-3-540-45070-2_12. URLhttp://dx.doi.org/10.1007/978-3-540-45070-2_12. → pages 108[33] J. G. Siek. A Language for Generic Programming. PhD thesis, Indiana University,August 2005. → pages 109114[34] J. G. Siek and A. Lumsdaine. Essential language support for generic programming. InProceedings of the 2005 ACM SIGPLAN Conference on Programming Language Designand Implementation, PLDI ’05, pages 73–84, New York, NY, USA, 2005. ACM. ISBN1-59593-056-6. doi:10.1145/1065010.1065021. URLhttp://doi.acm.org/10.1145/1065010.1065021. → pages 109[35] J. G. Siek and A. Lumsdaine. Language requirements for large-scale generic libraries.In GPCE ’05: Proceedings of the fourth international conference on GenerativeProgramming and Component Engineering, September 2005. → pages 109[36] C. Strachey. Fundamental concepts in programming languages. Higher Order Symbol.Comput., 13(1-2):11–49, Apr. 2000. ISSN 1388-3690. doi:10.1023/A:1010000313106.URL http://dx.doi.org/10.1023/A:1010000313106. → pages 3[37] P. J. Stuckey and M. Sulzmann. A theory of overloading. In Proceedings of the SeventhACM SIGPLAN International Conference on Functional Programming, ICFP ’02, pages167–178, New York, NY, USA, 2002. ACM. ISBN 1-58113-487-8.doi:10.1145/581478.581495. URL http://doi.acm.org/10.1145/581478.581495. → pages108[38] M. Sulzmann, M. M. T. Chakravarty, S. P. Jones, and K. Donnelly. System F with typeequality coercions. In Proceedings of the 2007 ACM SIGPLAN International Workshopon Types in Languages Design and Implementation, TLDI ’07, pages 53–66, New York,NY, USA, 2007. ACM. ISBN 1-59593-393-X. doi:10.1145/1190315.1190324. URLhttp://doi.acm.org/10.1145/1190315.1190324. → pages 55, 72, 109[39] M. Tofte and J.-P. Talpin. Region-based memory management. Information andComputation, 132(2):109 – 176, 1997. ISSN 0890-5401. doi:10.1006/inco.1996.2613.URL http://www.sciencedirect.com/science/article/pii/S0890540196926139. → pages 2,105[40] P. Wadler and S. Blott. How to make ad-hoc polymorphism less ad hoc. In Proceedingsof the 16th ACM SIGPLAN-SIGACT Symposium on Principles of ProgrammingLanguages, POPL ’89, pages 60–76, New York, NY, USA, 1989. ACM. ISBN0-89791-294-2. doi:10.1145/75277.75283. URLhttp://doi.acm.org/10.1145/75277.75283. → pages 3, 18, 108[41] S. Weirich, D. Vytiniotis, S. Peyton Jones, and S. Zdancewic. Generative typeabstraction and type-level computation. In Proceedings of the 38th Annual ACMSIGPLAN-SIGACT Symposium on Principles of Programming Languages, POPL ’11,pages 227–240, New York, NY, USA, 2011. ACM. ISBN 978-1-4503-0490-0.doi:10.1145/1926385.1926411. URL http://doi.acm.org/10.1145/1926385.1926411. →pages 109115Appendix AProof of type safety of RustInDefinition 6.1. Let Aµ = {w | ∃l.µ(l)=w}. In other words, Aµ is the image of µ.Define @µ ⊆ Aµ×Aµ as follows:• µ(l)@µ S 〈u〉 {xm : ln, x : l, xn : ln}• µ(l)@µ S 〈u〉 {xm : ln, x : l, xn : ln}I γDefinition 6.2 (Well-typed store). We say that Ω | Γ | Σ ` µ, meaning that the store µ is welltyped with respect to the environments Ω,Γ and the store typing Σ if1. dom(µ)= dom(Σ) and2. Ω |Γ |Σ`µ(l) :Σ(l) for every l ∈ dom(µ)3. @µ is a well-founded relation on the set Aµ = {w | ∃l.µ(l) = w}, i.e., it has no infinitedescending chains.Definition 6.3 (Constructed type). A constructed type is a type η that is of the form(),S 〈u〉 , fn(τ)→ τ,&u, (∃T,τ,ω), ∀X i.η or ∀ωi.η.Definition 6.4 (Consistency of coercion environment Ω). We say that Ω is consistent if thefollowing hold:1. If Ω` γ : S 〈u〉 ∼ η and η is a constructed type then η= S 〈u′〉 for some u′.2. If Ω` γ : fn(τi)→ τ∼ η and η is a constructed type then η= fn(τ′i)→ τ′ for some τ′i,τ′.3. If Ω` γ :&u1 ∼ η and η is a constructed type then η=&u′1 for some u′1.4. If Ω` γ : (∃T,τi,ω j)∼ η and η is a constructed type then η= (∃T,τ′i,ω′j) for some τ′i,ω′j.5. If Ω` γ :∀X i.σ∼ η′ where η′ is any type, then η′ =∀X i.σ′ for some σ′.1166. If Ω` γ :∀ωi.σ∼ η′ where η′ is any type, then η′ =∀ω′i.σ′ for some ω′i,σ′.Corollary A.1. Suppose consistent Ω. If Ω` γ : τ∼σ then σ ∈ STYPE.Lemma A.1 (Inversion lemma for typing terms). The following are all true:1. If Ω |Γ |Σ` let x : τ= e1 in e2 :σ then there is some type τ2 such that σ= τ2and Ω |Γ |Σ` e1 : τ1 and Ω |Γ, x : τ |Σ` e2 : τ2.2. If Ω |Γ |Σ` (lv := e) :σ then σ= () and Ω |Γ |Σ` lv : τ′ and Ω |Γ |Σ` e : τ′ for some τ′.3. If Ω | Γ |Σ` e(e i) :σ then Ω | Γ |Σ` e : fn(τi)→ τ and Ω |Γ |Σ` e i : τi and σ= τ for someτ and τi.4. If Ω |Γ |Σ` fn (xi : τ1){e} :σ then Ω |Γ, xi : τi |Σ` e : τ and σ= fn(τi)→ τ for some τ.5. If Ω |Γ |Σ` x :σ then (x :σ) ∈Γ.6. If Ω |Γ |Σ` l :σ then (l :σ) ∈Σ.7. If Ω |Γ |Σ`&lv :σ, then there is some type τ such that σ=&τ and Ω |Γ |Σ` lv : τ.8. If Ω |Γ |Σ`∗e :σ then there is some type τ such that σ= τ and Ω |Γ |Σ` e :&τ.9. If Ω |Γ |Σ` e.x :σ then Ω |Γ |Σ` e : S 〈u j〉 for some S and u j andS 〈X j〉 {xi :σi, x :σ′, xk :σk} ∈Ω for some X j, xi, xk,σi,σ′,σk and σ= [u j/X j]σ′.10. If Ω |Γ |Σ` S 〈u j〉 {xi : e i} :σ then S 〈X j〉 {xi :σi} ∈Ω,Ω |Γ |Σ` e i : [u j/X j]σi and σ= S 〈u j〉 for some X j,σi.11. If Ω |Γ |Σ` eI γ :σ then Ω` γ :σ′ ∼σ for some σ′ and Ω |Γ |Σ` e :σ′.12. If Ω | Γ | Σ ` e1; e2 : σ then there are some types τ1,τ2 such that Ω | Γ | Σ ` e1 : τ1, andΩ |Γ |Σ` e2 : τ2, and σ= τ2.13. If Ω |Γ |Σ` let (T, xi)= unpack e1 in e2 :σ then there are some τ,τi,ω such thatΩ |Γ |Σ` e1 :&(∃T,τi,ω) and Ω |Γ, xi : τi |Σ` e2 : τ and σ= τ with T 6∈ FV (τ).14. If Ω |Γ |Σ` pack (τ, e i,γ j) as &(∃T,τi,ω j) :σ then Ω |Γ |Σ` e i : [τ/T]τi,and Ω` γ j : [τ/T]ω j, and σ=&(∃T,τi,ω j).15. If Ω | Γ | Σ ` e[ui] : σ then there are some X i,σ′ such that Ω | Γ | Σ ` e : ∀X i.σ′ andσ= [ui/X i]σ′.16. If Ω |Γ |Σ`ΛX i.e :σ then there is some σ′ such that Ω |Γ, X i |Σ` e :σ′ and σ=∀X i.σ′.11717. If Ω |Γ |Σ` eJγiK :σ then there are some ωi such that Ω |Γ |Σ` e :∀ωi.σ and Ω` γi :ωi.18. If Ω | Γ | Σ ` Λci :ωi.e : σ then there is some σ′ such that Ω, ci :ωi | Γ | Σ ` e : σ′ andσ=∀ωi.σ′.19. If Ω |Γ |Σ` () :σ then σ= ().Proof. Immediate from the typing relation Ω |Γ |Σ` e :σ.Corollary A.2. If Ω |Γ |Σ` pv :σ then σ is a constructed type.Corollary A.3. If Ω |Γ |Σ` pw :σ then σ is a constructed type.Lemma A.2 (Canonical forms). Assume consistent Ω.1. If Ω |Γ |Σ` v :&τ then either:• v=&l for some l, or• v=&lI γ for some l and γ where Ω` γ :&τ′ ∼&τ for some type τ′.2. If Ω |Γ |Σ` v : S 〈u j〉 then either:• v= S 〈u j〉 {xi : vi} for some xi and vi, or• v= S 〈u′j〉 {xi : vi}I γ for some γ,u′j, xi and vi where Ω` γ : S 〈u′j〉 ∼ S 〈u j〉3. If Ω |Γ |Σ` v : fn(τi)→ τ then either:• v= fn (xi : τi){e} for some xi, e• v = fn (xi : τ′i){e}I γ for some xi, e,γ where Ω ` γ : fn(τ′i)→ τ′ ∼ fn(τi)→ τ for someτ′.4. If Ω |Γ |Σ` v :&(∃T,τi,ω j) then either:• v= pack (τ,vi,γ j) as &(∃T,τi,ω j) for some τ,vi,γ j or• v = (pack (τ,vi,γ j) as &(∃T,τ′i,ω′j)) I γ where Ω ` γ : &(∃T,τ′i,ω′j)) ∼ &(∃T,τi,ω j)for some γ,τ,vi,γ j,ω′j,τ′i.5. If Ω |Γ |Σ` v :∀X i.σ then either:• v=ΛX i.e for some e, or• v= (ΛX i.e)I γ where Ω` γ :∀X i.σ′ ∼∀X i.σ for some e,γ,σ′.6. If Ω |Γ |Σ` v :∀ωi.σ then either:118• v=Λci :ωi.e for some ci, e, or• v= (Λci :ω′i.e)I γ where Ω` γ :∀ω′i.σ′ ∼∀ωi.σ for some ci, e,γ,ω′i,σ′.Proof. If Ω | Γ | Σ ` v : σ then the following rules of the judgment Ω | Γ | Σ ` e : σ could havebeen used as the last rule in the derivation where the structure of e can match some value v:(t-fabs), (t-ref), (t-unit), (t-newstruct), (t-pack), (t-tabs), (t-cabs), (t-coerce).1. The only rules matching are (t-ref) for v =&l and (t-coerce) for v = pvI γ. By lemmaA.1 there is some σ such that Ω` γ :σ∼&τ and Ω | Γ |Σ` pv :σ. By corollary A.2 andconsistency of Ω, σ must be of the form &τ′ for some τ′. Then the last rule used to getΩ |Γ |Σ` pv :&τ′ can only be (t-ref) and pv=&l.2. Analogous to case 1. with rules (t-newstruct) and (t-coerce).3. Analogous to case 1. with rules (t-fabs) and (t-coerce).4. Analogous to case 1. with rules (t-pack) and (t-coerce).5. Analogous to case 1. with rules (t-tabs) and (t-coerce).6. Analogous to case 1. with rules (t-cabs) and (t-coerce).Lemma A.3 (Canonical forms for store values). Assume consistent Ω.1. If Ω |Γ |Σ`w : S 〈u j〉 and S 〈X j〉 {xi :σi} ∈Ω then either:• w= S 〈u j〉 {xi : l i} for some l i or• w= S 〈u′j〉 {xi : l i}I γ for some γ, l i,u′j where Ω` γ : S 〈u′j〉 ∼ S 〈u j〉.2. If Ω |Γ |Σ`w : τ and Ω` γ : τ∼ S 〈u j〉 with S 〈X j〉 {xi :σi} ∈Ω then either:• w= S 〈u′j〉 {xi : l i} and τ= S 〈u′j〉, or• w= S 〈u′j〉 {xi : l i}I γ′ where Ω` γ′ : S 〈u′j〉 ∼ τProof.1. The last typing rule used in the derivation Ω |Γ |Σ`w : S 〈u j〉 must be either(t-newstruct) or (t-coerce). If the last rule used is (t-newstruct) then w must have formS 〈u j〉 {xi : l i} as required.If the last rule used is (t-coerce), then w= pwI γ for some pw and γ.Furthermore, there is some σ such that119Ω` γ :σ∼ S 〈u j〉 and Ω |Γ |Σ` pw :σ.By corollary A.3 and consistency of Ω, σ must be of the form S 〈u′j〉 for some u′j. Thenthe last rule used in the derivation Ω | Γ | Σ ` pv : S 〈u′j〉 must be (t-newstruct) and pwmust have form S 〈u′j〉 {xi : l i}.2. Either τ is a constructed type or not. If it is a constructed type then by consistency ofΩ it is of the form S 〈u′j〉 and point 1 of this lemma applies.If τ is not a constructed type, then from examining all the typing rules only rule (t-coerce) can apply as the last rule used in the derivation Ω |Γ |Σ`w : τ.In consequence, there are some pw,σ′,γ′ such thatw= pwI γ′, and Ω` γ′ :σ′ ∼ τ, and Ω |Γ |Σ` pw :σ′.By (co-trans), Ω` γ′ ◦γ :σ′ ∼ S 〈u j〉and by corollary A.3 and consistency, σ′ = S 〈u′j〉 for some u′j.We can then use point 1 of this lemma to get pw= S 〈u′j〉 {xi : l i} for some l i.Lemma A.4 (Weakening for coercing typing). If Ω ` γ : ω then Ω,Ω′ ` γ : ω for any Ω′ suchthat the domains of Ω and Ω′ don’t overlap.Proof. Straightforward by inductions on derivations Ω` γ :ω.Lemma A.5 (Weakening for term typing). If Ω | Γ | Σ` e : σ then Ω,Ω′ | Γ,Γ′ | Σ,Σ′ ` e : σ forany Ω′,Γ′,Σ′ with no overlapping domains with Ω,Γ,Σ respectively.Proof. By straightforward rule induction on Ω | Γ |Σ` e :σ using lemma A.4 when required.Lemma A.6 (Term substitution). If Ω | Γ | Σ ` e′ : σ′ and Ω | Γ, x′ : σ′ | Σ ` e′′ : σ′′ thenΩ |Γ |Σ` [e′/x′]e′′ :σ′′Proof. By induction on derivations Ω |Γ, x′ :σ′ |Σ` e′′ :σ′′:• Case (t-let): e′′ = let x : τ1 = e1 in e2 and σ′′ = τ2.By bound variable renaming convention, we assume x 6= x′ and x 6∈ FV (e′),Then Ω |Γ, x′ :σ′ |Σ` e1 : τ1 and Ω |Γ, x′ :σ′, x : τ1 |Σ` e2 : τ2.By ind. hyp. Ω |Γ |Σ` [e′/x′]e1 : τ1 and Ω |Γ, x : τ1 |Σ` [e′/x′]e2 : τ2.By (t-let) Ω |Γ |Σ` let x : τ1 = [e′/x′]e1 in [e′/x′]e2 : τ2 where by definition of substitution(let x : τ1 = [e′/x′]e1 in [e′/x′]e2)≡ [e′/x′]e′′ as required.• Case (t-upd): Straightforward use of ind. hyp.120• Case (t-fapp): Straightforward use of ind. hyp.• Case (t-fabs): e′′ = fn (xi : τi){e} and σ′′ = fn(τi)→ τ.By bound variable renaming convention, we assume x′ 6∈ xi and xi 6∈ FV (e′).Then Ω |Γ, x′ :σ′, xi : τi |Σ` e : τ.By ind. hyp. Ω | Γ, xi : τi | Σ ` [e′/x′]e : τ which lets us prove Ω | Γ | Σ ` [e′/x′]e′′ : σ′′ asrequired.• Case (t-ref): Straightforward use of ind. hyp.• Case (t-deref): Straightforward use of ind. hyp.• Case (t-var): Ω |Γ, x′ :σ′ ` x :σ with (x :σ) ∈ (Ω |Γ, x′ :σ′).If x 6= x′ then Ω |Γ` x :σ is immediate.If x = x′ then σ= σ′ as (x : σ) ∈ (Ω | Γ, x′ : τ′) and Ω | Γ | Σ` [e′/x′]x : σ′ from the lemma’sassumption.• Case (t-unit): Vacuous.• Case (t-newstruct): Straightforward use of ind. hyp on e i with the fact[e′/x′](S 〈u j〉 {xi : e i})≡ S 〈u j〉 {xi : [e′/x′]e i}• Case (t-proj): Straightforward use of ind. hyp on e with the fact[e′/x′](e.x)≡ ([e′/x′]e).x• Case (t-seq): Straightforward use of ind. hyp.• Case (t-unpack): Similar to (t-let) assuming x′ 6∈ xi and xi 6∈ FV (e′).• Case (t-pack): e′′ = pack (τ, e i,γ j) as &(∃T,τi,ω j) and τ′′ =&(∃T,τi,ω j)Ω |Γ |Σ` [e′/x′]e i : [τ/T]τi i by ind. hyp.Ω |Γ |Σ` [e′/x′]e′′ :σ′′ by (t-pack).• Case (t-tapp): Straightforward use of ind. hyp.• Case (t-tabs): Straightforward use of ind. hyp.• Case (t-capp): Straightforward use of ind. hyp.• Case (t-cabs): Straightforward use of ind. hyp.• Case (t-coerce): Straightforward use of ind. hyp.• Case (t-loc): Trivial.121Lemma A.7 (Types are coercions). Ω` η : η∼ η for any η and Ω.Proof. By structural induction on η:• Case η= ():Ω` () : ()∼ () by (co-unit).• Case η= X :Ω` X : X ∼ X by (co-tvar).• Case η= A 〈ui〉:By ind. hyp. Ω` ui : ui ∼ ui for any Ω.Then Ω` A 〈ui〉 ∼ A 〈ui〉 by (co-atype).• Case η= (∃T,τi,ω j): Let ω j = u j ∼ u′j.By ind. hyp. Ω` τi ∼ τi and Ω` u j : u j ∼ u j and Ω` u′j : u′j ∼ u′j for any Ω.Then Ω` (∃T,τi,ω j) : (∃T,τi,ω j)∼ (∃T,τi,ω j) by (co-obj).• Case η= fn(τi)→ τBy ind. hyp. Ω` τi : τi ∼ τi and Ω` τ : τ∼ τ for any Ω.Then by (co-fun) Ω` fn(τi)→ τ : fn(τi)→ τ∼ fn(τi)→ τ• Case η=&u′:By ind. hyp. Ω` u′ : u′ ∼ u′.Then by (co-ref) Ω`&u′ :&u′ ∼&u′.• Case η= S 〈ui〉:By ind. hyp. Ω` ui : ui ∼ ui.Then by (co-struct) Ω` S 〈ui〉 : S 〈ui〉 ∼ S 〈ui〉.• Case η=∀X i.η.By ind. hyp. Ω` η : η∼ η.Then by (co-tabs) Ω`∀X i.η : X i.η∼ X i.η.122• Case η=∀ωi.η.Let ωi = ui ∼ u′i.By ind. hyp. Ω` η : η∼ η, and Ω` ui : ui ∼ ui, and Ω` u′i : u′i ∼ u′i.Then by (co-cabs) Ω`∀ωi.η : (∀ωi.η)∼ (∀ωi.η).Lemma A.8 (Type substitution in coercions). If Ω` γ :ϑ then [u/X ]Ω` [u/X ]γ : [u/X ]ϑ.Proof. By induction on derivations Ω` γ :ϑ:• Case (co-var): Ω` c :ϑ.Then (c : [u/X ]ϑ) ∈ [u/X ]Ω.and [u/X ]Ω` c : [u/X ]ϑ as required.• Case (co-sym): Straightforward use of ind. hyp.• Case (co-trans): Straightforward use of ind. hyp.• Case (co-tapp): Straightforward use of ind. hyp.• Case (co-tabs): Straightforward use of ind. hyp.• Case (co-cabs): Straightforward use of ind. hyp.• Case (co-unit): Ω` () : ()∼ ().Then [u/X ]Ω` [u/X ]() : [u/X ]()∼ [u/X ]() as required since [u/X ]()= ().• Case (co-tvar): Ω` X ′ : X ′ ∼ X ′.If X = X ′ then [u/X ]Ω` u : u∼ u by lemma A.7.Otherwise [X /u]X ′ = X ′ and by (co-tvar) [u/X ]Ω` X ′ : X ′ ∼ X ′ as required.• Case (co-atype): Ω` A 〈γi〉 : A 〈ui〉 ∼ A 〈u′i〉.By ind. hyp. [u/X ]Ω` [u/X ]γi : [u/X ]ui ∼ [u/X ]u′i.Then by (co-atype) and def. of substitution[u/X ]Ω` [u/X ]A 〈γi〉 : [u/X ]A 〈ui〉 ∼ [u/X ]A 〈u′i〉 as required.• Case (co-struct): Straightforward use of ind. hyp.• Case (co-ref): Straightforward use of ind. hyp.• Case (co-obj): Straightforward use of ind. hyp. assuming X 6= T by the bound variablerenaming convention.123• Case (co-fun): Straightforward use of ind. hyp.• Case (co-deref): Straightforward use of ind. hyp.• Case (co-spar): Straightforward use of ind. hyp.• Case (co-farg): Straightforward use of ind. hyp.• Case (co-fret): Straightforward use of ind. hyp.• Case (co-objf): Straightforward use of ind. hyp. assuming T 6= X by the bound variablerenaming assumption.• Case (co-objc-l): Straightforward use of ind. hyp. assuming T 6= X .• Case (co-objc-r): Straightforward use of ind. hyp. assuming T 6= X .• Case (co-coer): Straightforward use of ind. hyp.• Case (co-coer-l): Straightforward use of ind. hyp.• Case (co-coer-r): Straightforward use of ind. hyp.Lemma A.9 (Type substitution). If Ω |Γ, X |Σ` e :σ then[u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]e : [u/X ]σ.Proof. By induction on derivations Ω |Γ, X |Σ` e :σ.• Case (t-let): Ω |Γ, X |Σ` let x : τ1 = e1 in e2 : τ2.By ind. hyp. [u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]e1 : [u/X ]τ1 and[u/X ]Ω | [u/X ]Γ, x : [u/X ]τ1 | [u/X ]Σx : τ1 ` [u/X ]e2 : [u/X ]τ2.Then by rule (t-let) and the definition of substitution,[u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ](let x : τ1 = e1 in e2 : τ2) : [u/X ]τ2• Case (t-upd): Straightforward use of ind. hyp. as above.• Case (t-fapp): Straightforward use of ind. hyp.• Case (t-fabs): Straightforward use of ind. hyp.• Case (t-ref): Straightforward use of ind. hyp.• Case (t-deref): Straightforward use of ind. hyp.124• Case (t-var): Ω |Γ, X |Σ` x :σ.Then (x : [u/X ]σ) ∈ [u/X ]Γ which lets us prove [u/X ]Ω | [u/X ]Γ | [u/X ]Σ` x : [u/X ]σ.• Case (t-unit): Vacuous.• Case (t-newstruct): Straightforward use of ind. hyp.• Case (t-proj): Straightforward use of ind. hyp.• Case (t-seq): Straightforward use of ind. hyp.• Case (t-unpack): Ω |Γ, X |Σ` let (T, xi)= unpack e1 in e2 : τ.By bound variable renaming convention, assume T 6= X .By ind. hyp. [u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]e1 : [u/X ](&(∃T,τi,ω j)) and[u/X ]Ω | [u/X ]Γ,T, xi : [u/X ]τi | [u/X ]Σ` [u/X ]e2 : [u/X ]τ.[u/X ](&(∃T,τi,ω j))=&(∃T, [u/X ]τi, [u/X ]ω j) by definition of substitution.[u/X ]Ω | [u/X ]Γ | [u/X ]Σ ` let (T, xi) = unpack [u/X ]e1 in [u/X ]e2 : [u/X ]τ by (t-unpack)as required.• Case (t-pack): Ω |Γ, X |Σ` pack (τ, e i,γi) as &(∃T,τi,γ j) :&(∃T,τi,γ j).Assume T 6= X by bound variable renaming convention.[u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]e i : [u/X ][τ/T]τi by ind. hyp.[u/X ]Ω` [u/X ]γ j : [u/X ][τ/T]ω j by lemma A.8.[u/X ][τ/T]τi ≡ [[u/X ]τ/T][u/X ]τi and[u/X ][τ/T]ω j ≡ [[u/X ]τ/T][u/X ]ω j by definition of substitution.Then[u/X ]Ω | [u/X ]Γ | [u/X ]Σ` pack ([u/X ]τ, [u/X ]e i, [u/X ]γ j) as &(∃T, [u/X ]τi, [u/X ]ω j):&(∃T, [u/X ]τi, [u/X ]ω j)by (t-pack) as required.• Case (t-tapp): Ω |Γ, X |Σ` e[ui] : [ui/X i]σ.Assume X 6∈ X i.By ind. hyp. [u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]e : [u/X ]∀X i.σ.[u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]e[[u/X ]ui] : [[u/X ]ui/X i][u/X ]τ by (t-tapp) as required.• Case (t-tabs): Ω |Γ, X |Σ`ΛX i.e :∀X i.τ.Assume X 6∈ X i.By ind. hyp. [u/X ]Ω | [u/X ]Γ, X i | [u/X ]Σ` [u/X ]e : [u/X ]τ.By (t-tabs) [u/X ]Ω | [u/X ]Γ | [u/X ]Σ`ΛX i.[u/X ]e :∀X i.[u/X ]τ.ΛX i.[u/X ]e ≡ [u/X ](ΛX i.e) and ∀X i.[u/X ]σ ≡ [u/X ](∀X i.τ) by def. of substitution asrequired.125• Case (t-capp): Ω |Γ, X |Σ` eJγiK :σ.Ω |Γ, [u/X ]Γ′ |Σ` [u/X ]e : [u/X ](∀ωi.σ) by ind. hyp.Ω` [u/X ]γi : [u/X ]ωi by lemma A.8.[u/X ](∀ωi.σ)≡∀[u/X ]ωi.[u/X ]σ by def. of substitution.Ω |Γ, [u/X ]Γ′ |Σ` [u/X ]eJ[u/X ]γiK by (t-capp).[u/X ]eJ[u/X ]γiK≡ [u/X ](eJγiK) by def. of substitution as required.• Case (t-cabs): Ω |Γ, X |Σ`Λci :ωi.e :∀ωi.σ.Ω, ci : [u/X ]ωi |Γ, [u/X ]Γ′ |Σ` [u/X ]e : [u/X ]σ by ind. hyp.Ω |Γ, [u/X ]Γ′ |Σ`Λci : [u/X ]ωi.[u/X ]e :∀[u/X ]ωi.[u/X ]σ by (t-cabs) as required.• Case (t-coerce): Ω |Γ, X |Σ` eI γ :σ2.[u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]e : [u/X ]σ1 by ind. hyp.[u/X ]Ω` [u/X ]γ : [u/X ]σ1 ∼ [u/X ]σ2 by lemma A.8.[u/X ]Ω | [u/X ]Γ | [u/X ]Σ` [u/X ]eI [u/X ]γ : [u/X ]σ2 by (t-coerce) as required.• Case (t-loc): Ω |Γ, X |Σ` l :σ.Then (l : [u/X ]σ) ∈ [u/X ]Ωand [u/X ]Ω | [u/X ]Γ | [u/X ]Σ` l : [u/X ]σ by (t-loc) as required.Lemma A.10 (Coercion substitution). If Ω, c :ϑ′ ` γ :ϑ and Ω` γ′ :ϑ′ then Ω` [γ′/c]γ :ϑ.Proof. Straightforward by induction on derivations Ω, c :ω′ ` γ :ϑ.Lemma A.11 (Coercion substitution in terms). If Ω, c : ω | Γ | Σ ` e : σ and Ω ` γ : ω thenΩ |Γ |Σ` [γ/c]e :σ.Proof. By induction on derivations Ω, c :ω |Γ |Σ` e :σ assuming Ω` γ :ω in all cases.Mostly straightforward use of induction hypothesis except in the following cases:• Case (t-pack): Ω, c :ω |Γ |Σ` pack (τ, e i,γ j) as &(∃T,τi,ω j) :&(∃T,τi,ω j) and Ω` γ :ω.Ω |Γ |Σ` [γ/c]e i : [τ/T]τi by ind. hyp.Ω` [γ/c]γ j : [τ/T]γ j by lemma A.10.Ω |Γ |Σ` pack (τ, [γ/c]e i, [γ/c]γ j) as &(∃T,τi,ω j) :&(∃T,τi,ω j)by (t-pack) as required.• Case (t-capp): Ω, c :ω |Γ |Σ` eJγ jK :σ and Ω` γ :ω.Ω |Γ |Σ` [γ/c]e :∀ω j.σ by ind. hyp.Ω` [γ/c]γ j : [ui/X i]ω jjby lemma A.10.Ω |Γ |Σ` [γ/c]eJ[γ/c]γiK :σ by (t-capp) as required.126• Case (t-cabs): Ω, c :ω |Γ |Σ`Λc j :ω j.e :∀ω j.σ.Ω, c j :ω j |Γ |Σ` [γ/c]e :σ by ind. hyp.We can assume c 6∈ c j because of the bound variable renaming convention.Then Ω |Γ |Σ`Λc j :ω j.[γ/c]e :∀ω j.σ as required.• Case (t-coerce): Ω, c :ω |Γ |Σ` eI γ′ :σ2.Ω |Γ |Σ` [γ/c]e :σ1 by ind. hyp.Ω` [γ/c]γ′ :σ1 ∼σ2 by lemma A.10.Then Ω |Γ |Σ` [γ/c]eI [γ/c]γ′ :σ2 by (t-coerce) as required.Lemma A.12 (Type soundness of alloc). Suppose Ω |Γ |Σ` v :σ and Ω |Γ |Σ`µ.If alloc(µ,v)= 〈µ′, l〉 then there is some Σ′ ⊇Σ such thatl 6∈ dom(µ) and Ω |Γ |Σ′ `µ′ and Ω |Γ |Σ′ ` l :σ.Proof. By structural induction on v:• Case v ∈ STOREVAL:Suppose Ω |Γ |Σ` v :σ and Ω |Γ |Σ`µ.By definition of alloc, alloc(µ,v)= 〈µ[l 7→ v], l〉 where l 6∈ dom(µ).Let Σ′ =Σ, l :σ. Then Ω |Γ |Σ′ ` l :σ by (t-loc) and Ω |Γ |Σ′ `µ′ asthere is no w such that w@µ v.• Case v= S 〈u j〉 {xi : vi}:Suppose Ω |Γ |Σ` S 〈u j〉 {xi : vi} :σ and Ω |Γ |Σ`µ0.By lemma A.1, there are some X j,σi such thatΩ |Γ |Σ` vi : [u j/X j]σi and S 〈X j〉 {xi :σi} ∈Ω and σ= S 〈u j〉.By definition, alloc(µ0,S 〈u j〉 {xi : vi})= 〈µ′, l〉where 〈µi, l i〉 = alloc(µi−1,vi)iand µ′ =µi[l 7→ S 〈u j〉 {xi : l i}] and l 6∈ dom(µi).Lemma A.5 gives us Ω |Γ |Σ′ ` vi : [u j/X j]σi for any Σ′ ⊇Σ.This allows us to use the induction hypothesis i times to getl i 6∈ dom(µi−1) and Ω |Γ |Σi `µi i and Ω |Γ |Σi ` l i : [u j/X j]σiifor some Σi ⊇Σi−1 i. Let Σ′ =Σi.By lemma A.5, Ω |Γ |Σ′ ` l i : [u j/X j]σi.Then by (t-newstruct) Ω |Γ |Σ′ ` S 〈u j〉 {xi : l i} : S 〈u j〉.Let Σ′′ =Σ′, l : S 〈u j〉. Then Ω |Γ |Σ′′ ` l : S 〈u j〉 by (t-loc).127µ′(l i)@µ′ S 〈u j〉 {xi : l i}iby def. of @µ′ .Since l is not mentioned in µi and @µi is well-founded,we conclude that @µ′ is well-founded and Ω |Γ |Σ′′ `µ′.• Case v= S 〈u j〉 {xi : vi}I γ:Suppose Ω |Γ |Σ` S 〈u j〉 {xi : vi}I γ :σ and Ω |Γ |Σ`µ0.By lemma A.1, there are some τ, X j,σi such that:Ω` γ : S 〈u j〉 ∼ τ andΩ |Γ |Σ` vi : [u j/X j]σi andS 〈X j〉 {xi :σi} ∈Ω andσ= τ.By definition, alloc(µ0,S 〈u j〉 {xi : vi}I γ)= 〈µi[l 7→ S 〈u j〉 {xi : l i}I γ], l〉where 〈µi, l i〉 = alloc(µi−1,vi)i and l 6∈ dom(µ0).Lemma A.5 gives us Ω |Γ |Σ′ ` vi : [u j/X j]σi for any Σ′ ⊇Σ.This allows us to use the induction hypothesis i times to getl i 6∈ dom(µi−1) and Ω |Γ |Σi `µi i and Ω |Γ |Σi ` l i : [u j/X j]σiifor some Σi ⊇Σi−1 i. Let Σ′ =Σi.By lemma A.5, Ω |Γ |Σ′ ` l i : [u j/X j]σi.Then by (t-newstruct) Ω |Γ |Σ′ ` S 〈u j〉 {xi : l i} : S 〈u j〉and by (t-coerce) Ω |Γ |Σ′ ` S 〈u j〉 {xi : l i}I γ : S 〈u j〉.Let Σ′′ =Σ′, l : τ. Then Ω |Γ |Σ′′ ` l : τ by (t-loc)and Ω |Γ |Σ′′ `µi[l 7→ S 〈u j〉 {xi : l i}I γ]by the same argument as in the previous case.Lemma A.13 (Lifting). If Ω` γi : ui ∼ u′i then Ω` [γi/X i]η : [ui/X i]η∼ [u′i/X i]η.Proof. By structural induction on u supposing in all cases that Ω` γi : ui ∼ u′i:• Case η= ():Ω` () : ()∼ () by (co-unit).• Case η= X :If X 6∈ X i then the case holds by (co-tvar).Otherwise, [γ/X ] ∈ [γi/X i] and Ω` γ : u1 ∼ u2 for some γ,u1,u2.Then Ω` [γi/X i]γ : [ui/X i]u1 ∼ [u′i/X i]u2 as required.128• Case η= A 〈u j〉:By ind. hyp. Ω` [γi/X i]u j : [ui/X i]u j ∼ [u′i/X i]u jj.Then by (co-atype) and def. of substitutionΩ` [γi/X i]A 〈u j〉 : [γi/X i]A 〈u j〉 ∼ [γi/X i]A 〈u j〉 as required.• Case η= (∃T,τk,ω j):Straightforward use of the induction hypothesis as in the previous case.• Case η= fn(τi)→ τStraightforward use of the induction hypothesis as in the previous case.• Case η=&u′:Straightforward use of the induction hypothesis as in the previous case.• Case η= S 〈ui〉:Straightforward use of the induction hypothesis as in the previous case.• Case η=∀X j.η:Straightforward use of the induction hypothesis as in the previous case.• Case η=∀ω j.η:Straightforward use of the induction hypothesis as in the previous case.Lemma A.14 (Value-preserving coercion). If Ω |Γ |Σ` vI γ :σthen vII γ= v′ for some v′ where Ω |Γ |Σ` v′ :σ.Proof. By cases on v:• Case v= pv:Then by def. pvII γ= pvI γ and pvI γ ∈VAL.• Case v= pvI γ′:Then by def. pvI γ′II γ= pvI (γ′ ◦γ).and pvI (γ′ ◦γ) ∈VAL.From lemma A.1 we get Ω` γ :σ′ ∼σ and Ω` γ′ :σ′′ ∼σ′ and Ω |Γ |Σ` pv :σ′′.Then by (co-trans) Ω` γ′ ◦γ :σ′′ ∼σand by (t-coerce) Ω |Γ |Σ` pvI (γ′ ◦γ) :σ as required.129Lemma A.15 (Type soundness of update). Suppose Ω | Γ | Σ ` v : σ and Ω | Γ | Σ ` l : σ andΩ |Γ |Σ`µ.Then updateΩ(µ, l,v)=µ′ where Ω |Γ |Σ`µ′.Proof. By structural induction on v:• Case v= S 〈u j〉 {xi : vi}:Suppose Ω |Γ |Σ` S 〈u j〉 {xi : vi} :σ and Ω |Γ |Σ` l :σ and Ω |Γ |Σ`µ0.By lemma A.1, there are some X j,σi such thatΩ |Γ |Σ` vi : [u j/X j]σi and S 〈X j〉 {xi :σi} ∈Ω and σ= S 〈u j〉.From Ω |Γ |Σ`µ0 and Ω |Γ |Σ` l : S 〈u j〉 we can deduce Ω |Γ |Σ`µ0(l) : S 〈u j〉.From lemma A.3 we know that eitherµ0(l)= S 〈u j〉 {xi : l i} for some l i orµ0(l)= S 〈u′j〉 {xi : l i}I γ for some γ, l i,u′j where Ω` γ : S 〈u′j〉 ∼ S 〈u j〉.We must consider both cases separately:– Case µ0(l)= S 〈u j〉 {xi : l i}:Then by definition of update,updateΩ(µ0, l,S 〈u j〉 {xi : vi})=µi where µi =updateΩ(µi−1, l i,vi).By lemma A.1, Ω |Γ |Σ` l i : [u j/X j]σiand by ind. hyp. Ω |Γ |Σ`µi as required.– Case µ0(l)= S 〈u′j〉 {xi : l i}I γ:Then, by definition of update,updateΩ(µ0, l,S 〈u j〉 {xi : vi})=µiwhere µi =updateΩ(µi−1, l i,vi II [γ j/X j]σi)and γ j = spar ( j,sym γ).By lemma A.1, Ω |Γ |Σ` S 〈u′j〉 {xi : l i} : S 〈u′j〉and Ω |Γ |Σ` l i : [u′j/X j]σi.By (co-sym) and (co-spar), Ω` γ j : u j ∼ u′j.By lemma A.13, Ω |Γ |Σ` vi I [γ j/X j]σi : [u′j/X j]σiand by lemma A.14,Ω |Γ |Σ` vi II [γ j/X j]σi : [u′j/X j]σi where vi II [γ j/X j]σi ∈VAL.Then, by the induction hypothesis, Ω |Γ |Σ`µi as required.• Case v= S 〈u j〉 {xi : vi}I γ:Suppose Ω |Γ |Σ` S 〈u j〉 {xi : vi}I γ :σ and Ω |Γ |Σ` l :σ and Ω |Γ |Σ`µ0.130From lemma A.1 we get Ω` γ : S 〈u j〉 ∼σ as well asΩ |Γ |Σ` vi : [u j/X j]σi and S 〈X j〉 {xi :σi} ∈Ωfor some X j,σi.From Ω |Γ |Σ`µ0 and Ω |Γ |Σ` l :σ we can deduce Ω |Γ |Σ`µ0(l) :σ.By lemma A.3, since Ω` sym γ :σ∼ S 〈u j〉 by (co-sym), eitherµ0(l)= S 〈u′j〉 {xi : l i} and σ= S 〈u′j〉 for some u′j, l i orµ0(l)= S 〈u′j〉 {xi : l i}I γ′ where Ω` γ′ : S 〈u′j〉 ∼σ for some u′j, l i.We consider both cases separately:– Case µ0(l)= S 〈u′j〉 {xi : l i}:Then by definition of update,updateΩ(µ0, l,S 〈u j〉 {xi : vi}I γ)=µiwhere µi =updateΩ(µi−1, l i,vi II [γ j/X j]σi)and γ j = spar ( j,γ).From lemma A.1 we get Ω |Γ |Σ` l i : [u′j/X j]σi.Using (co-spar) we get Ω` γ j : u j ∼ u′j.By lemma A.13, Ω |Γ |Σ` vi I [γ j/X j]σi : [u′j/X j]σiand by lemma A.14,Ω |Γ |Σ` vi II [γ j/X j]σi : [u′j/X j]σi where vi II [γ j/X j]σi ∈VAL.Then, by the induction hypothesis, Ω |Γ |Σ`µi as required.– Case µ0(l)= S 〈u′j〉 {xi : l i}I γ′:Then by definition of update,updateΩ(µ0, l,S 〈u j〉 {xi : vi}I γ)=µiwhere µi =updateΩ(µi−1, l i,vi II [γ j/X j]σi)and γ j = spar ( j,γ◦ sym γ′).From lemma A.1 we get Ω |Γ |Σ` l i : [u′j/X j]σi.Using (co-sym), (co-trans) and (co-spar) we get Ω` γ j : u j ∼ u′j.By lemma A.13, Ω |Γ |Σ` vi I [γ j/X j]σi : [u′j/X j]σiand by lemma A.14,Ω |Γ |Σ` vi II [γ j/X j]σi : [u′j/X j]σi where vi II [γ j/X j]σi ∈VAL.Then, by the induction hypothesis, Ω |Γ |Σ`µi as required.• Case v ∈ PVAL:Then µ′ =µ[l 7→ v].Ω |Γ |Σ` v :σ and Ω |Γ |Σ` l :σ by assumptionand there is no possible w@µ′ v which lets us conclude Ω |Γ |Σ`µ′.131Lemma A.16 (Type soundness of getValue). If Ω |Γ |Σ`µ and Σ(l)=σ thenΩ |Γ |Σ` getValue(µ, l) :σ.Proof. From the def. of Ω | Γ | Σ ` µ we know that @µ is a well founded relation on the ele-ments in the image of µ. We then prove the lemma by induction on l assuming the inductionhypothesis for all l′ where µ(l′)@µ µ(l).• Case µ(l)= S 〈u j〉 {xi : l i}:Suppose Ω |Γ |Σ`µ and Ω |Γ |Σ` l :σ.Then S 〈u j〉 {xi : l i} :σ.From lemma A.1 we getS 〈X j〉 {xi :σi} ∈Ω andΩ |Γ |Σ` l i : [u j/X j]σi andσ= S 〈u j〉 for some X j,σi.By def., getValue(µ, l)= S 〈u j〉 {xi : getValue(µ, l i)}.By ind. hyp. Ω |Γ |Σ` getValue(µ, l i) : [u j/X j]σii.Then by (t-newstruct), Ω |Γ |Σ` S 〈u j〉 {xi : getValue(µ, l i)} : S 〈u j〉 as required.• Case µ(l)= S 〈u j〉 {xi : l i}I γ:Suppose Ω |Γ |Σ`µ and Ω |Γ |Σ` l :σ.Then S 〈u j〉 {xi : l i}I γ :σ.From lemma A.1 we getΩ` γ : S 〈u j〉 ∼σ andΩ |Γ |Σ` S 〈u j〉 {xi : l i} andS 〈X j〉 {xi :σi} ∈Ω andΩ |Γ |Σ` l i : [u j/X j]σifor some X j,σi.By def. getValue(µ, l)= S 〈u j〉 {xi : getValue(µ, l i)}.By ind. hyp. Ω |Γ |Σ` getValue(µ, l i) : [u j/X j]σii.Then by (t-newstruct) and (t-coerce) Ω | Γ | Σ ` S 〈u j〉 {xi : getValue(µ, l i)} I γ : σ asrequired.• Case µ(l)=w where w matches neither of the above forms:getValue(µ, l)=µ(l) as required.132Theorem 6.1 (Preservation). Suppose Ω is a consistent environment.1. If Ω |Γ |Σ` e :σ and Ω |Γ |Σ`µ and 〈µ, e〉 Ω−−→〈µ′, e′〉then, there is some store typing Σ′ ⊇Σ such thatΩ |Γ |Σ′ ` e′ :σ and Ω |Γ |Σ′ `µ′.2. If Ω |Γ |Σ` lv : τ and Ω |Γ |Σ`µ and 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉then, there is some store typing Σ′ ⊇Σ such thatΩ |Γ |Σ′ ` lv′ : τ and Ω |Γ |Σ′ `µ′.Proof. By simultaneous induction on derivations 〈µ, e〉 Ω−−→〈µ′, e′〉 and 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉.• Case (e-let1):Suppose Ω |Γ |Σ` let x : τ= v in e2 :σ and Ω |Γ |Σ`µ and〈µ, let x : τ= v in e2〉 Ω−−→〈µ′, [l/x]e2〉where 〈µ′, l〉 = alloc(µ,v)From lemma A.1 we know that Ω | Γ | Σ` v : τ and Ω | Γ, x : τ | Σ` e2 : τ2 and σ= τ2 forsome τ2.From lemma A.12 we know that Ω |Γ |Σ′ `µ′ and Ω |Γ |Σ′ ` l : τ for some Σ′ ⊇Σ.We can then use lemma A.6 to conclude that Ω |Γ |Σ′ ` [l/x]e2 : τ2• Case (e-let2):Suppose Ω |Γ |Σ` let x : τ= e in e2 :σ and Ω |Γ |Σ`µ and〈µ, let x : τ= e in e2〉 Ω−−→〈µ′, let x : τ= e′ in e2〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.Ω |Γ |Σ` e : τ and Ω |Γ, x : τ |Σ` e2 : τ2 and σ= τ2 for some τ2 by lemma A.1.Ω |Γ |Σ′ ` e′ : τ and Ω |Γ |Σ′ `µ′. for some Σ′ ⊇Σ by ind. hyp.Ω |Γ |Σ′ ` let x : τ= e′ in e2 : τ2 by lemma A.5 and (t-let) as required.• Case (e-upd1):Suppose Ω |Γ |Σ` lv := e :σ and Ω |Γ |Σ`µ and〈µ, lv := e〉 Ω−−→〈µ′, lv′ := e〉where 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉.By lemma A.1 there is some τ such that Ω |Γ |Σ` lv : τ and Ω |Γ |Σ` e : τ and σ= ().By ind. hyp. there is some Σ′ ⊇Σ such that Ω |Γ |Σ′ `µ′ and Ω |Γ |Σ′ ` lv′ : τ.Then Ω |Γ |Σ′ ` lv′ := e : () by lemma A.5 and (t-upd) as required.133• Case (e-upd2):Suppose Ω |Γ |Σ` l := v :σ and Ω |Γ |Σ`µ and〈µ, l := v〉 Ω−−→〈µ′,()〉where µ′ =updateΩ(µ, l,v).By lemma A.1 there is some τ such that Ω |Γ |Σ` l : τ and Ω |Γ |Σ` e : τ and σ= ().Ω |Γ |Σ`µ′ by lemma A.15.By (t-unit) Ω |Γ |Σ` () : () as required.• Case (e-upd3):Suppose Ω |Γ |Σ` (lI γ) := e :σ and Ω |Γ |Σ`µ and〈µ, (lI γ) := e〉 Ω−−→〈µ, l := (eI sym γ)〉.By lemma A.1 there is some τ such that Ω |Γ |Σ` lI γ : τ and Ω |Γ |Σ` e : τ and σ= ().Using lemma A.1 again with corollary A.1 we get Ω | Γ | Σ ` l : τ′ and Ω ` γ : τ′ ∼ τ forsome type τ′.Using (co-sym) we get Ω` sym γ : τ∼ τ′.Using (t-coerce) we get Ω |Γ |Σ` eI sym γ : τ′.Finally, using (t-upd) we can prove Ω |Γ |Σ` l := (eI sym γ) : () as required.• Case (e-upd4):Suppose Ω |Γ |Σ` l := e :σ and Ω |Γ |Σ`µ and〈µ, l := e〉 Ω−−→〈µ′, l := e′〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.By lemma A.1 there is some τ such that Ω |Γ |Σ` l : τ and Ω |Γ |Σ` e : τ and σ= ().By ind. hyp. Ω |Γ |Σ′ `µ′ and Ω |Γ |Σ′ ` e′ : τ for some Σ′ ⊇Σ.By lemma A.5 and (t-upd) Ω |Γ |Σ′ ` l := e′ : () as required.• Case (e-loc):Suppose Ω |Γ |Σ` l :σ and Ω |Γ |Σ`µ and〈µ, l〉 Ω−−→〈µ,v〉where v= getValue(µ, l).From lemma A.1 we know Σ(l)=σ.From lemma A.16 we get Ω |Γ |Σ` v :σ as required.• Case (e-deref1):134Suppose Ω |Γ |Σ`∗&l :σ and Ω |Γ |Σ`µ and〈µ,∗&l〉 Ω−−→〈µ, l〉.Using lemma A.1 we get that Ω |Γ |Σ`&l :&τ and σ= τ for some τ.Using lemma A.1 again we get Ω |Γ |Σ` l : τ as required.• Case (e-deref2):Suppose Ω |Γ |Σ`∗(&lI γ) :σ and Ω |Γ |Σ`µ and〈µ,∗(&lI γ)〉 Ω−−→〈µ′, lI∗γ〉.Using lemma A.1 we get Ω |Γ |Σ`&lI γ :&τ and σ= τ for some τ.Using lemma A.1 again we get Ω |Γ |Σ`&l : τ′ and Ω` γ : τ′ ∼&τ for some τ′.Another use of lemma A.1 gives us Ω |Γ |Σ` l : τ′′ and τ′ =&τ′′ for some τ′′.By (co-deref) we get Ω |Γ |Σ`∗γ : τ′′ ∼ τ.By (t-coerce) we can prove Ω |Γ |Σ` lI∗γ : τ as required.• Case (e-deref3):Suppose Ω |Γ |Σ`∗e :σ and Ω |Γ |Σ`µ and〈µ,∗e〉 Ω−−→〈µ′,∗e′〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.From lemma A.1 we get Ω |Γ |Σ` e :&τ and σ= τ for some τ.By ind. hyp. Ω |Γ |Σ′ ` e′ :&τ and Ω |Γ |Σ′ `µ′ for some Σ′ ⊇Σ.By (t-deref) Ω |Γ |Σ′ `∗e′ : τ as required.• Case (e-ref1):Suppose Ω |Γ |Σ`&lv :σ and Ω |Γ |Σ`µ and〈µ,&lv〉 Ω−−→〈µ′,&lv′〉where 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉.From lemma A.1 we get Ω |Γ |Σ` lv : τ and σ=&τ for some τ.By ind. hyp. Ω |Γ |Σ′ ` lv′ : τ and Ω |Γ |Σ′ `µ′ for some Σ′ ⊇Σ.With rule (t-ref) we can prove Ω |Γ |Σ′ `&lv′ :&τ as required.• Case (e-ref2):Suppose Ω |Γ |Σ`&(lI γ) :σ and Ω |Γ |Σ`µ and〈µ,&(lI γ)〉 Ω−−→〈µ,&lI&γ〉.From lemma A.1 we get Ω |Γ |Σ` lI γ : τ and σ=&τ for some τ.135Using lemma A.1 again we get Ω |Γ |Σ` l : τ′ and Ω` γ : τ′ ∼ τ for some type τ.By (co-ref) we get Ω`&γ :&τ′ ∼&τ.By (t-ref) we get Ω |Γ |Σ`&l :&τ′.Finally, by (t-coerce) we get Ω |Γ |Σ`&lI&γ :&τ as required.• Case (e-fapp1):Suppose Ω |Γ |Σ` fn (xi : τi){e}(vi) :σ and Ω |Γ |Σ`µ and〈µ, fn (xi : τi){e}(vi)〉 Ω−−→〈µi, [l i/xi]e〉where µ0 =µ and 〈µi, l i〉 = alloc(µi−1,vi)i.From lemma A.1 we get Ω |Γ |Σ` fn (xi : τi){e} : fn(τ′i)→ τ and Ω |Γ |Σ` vi : τ′i and σ= τfor some τ and τ′i.Using lemma A.1 again we get Ω |Γ, xi : τi |Σ` e : τ and τi = τ′i.From lemma A.12 we get Ω |Γ |Σ′ `µi and with lemma A.5 we have Ω |Γ |Σ′ ` l i : τi forsome Σ′ ⊇Σ.Then, using lemmas A.5 and A.6 we get Ω |Γ |Σ′ ` [l i/xi]e : τ as required.• Case (e-fapp2):Suppose Ω |Γ |Σ` (fn (xi : τi){e}I γ)(e i) :σ and Ω |Γ |Σ`µ and〈µ, (fn (xi : τi){e}I γ)(e i)〉 Ω−−→〈µ, fn (xi : τi){e}(e i I γi)I γR〉where γi = sym (farg (i,γ)) and γR = fret γ.From lemma A.1 we get Ω | Γ | Σ` fn (xi : τi){e}I γ : fn(τ′i)→ τ and Ω |Γ |Σ` e i : τ′i andσ= τfor some τ and τ′i.Using lemma A.1 again we get Ω` γ : fn(τ′′i )→ τ′ ∼ fn(τ′i)→ τand Ω |Γ |Σ` fn (xi : τi){e} : fn(τ′′i )→ τ′.Yet another use of lemma A.1 gives us Ω |Γ, xi : τi |Σ` e : τ′ and τi = τ′′i .Using (co-farg) and (co-sym) we get Ω` γi : τ′i ∼ τi.Using (co-fret) we get Ω` γR : τ′ ∼ τ.By (t-coerce) Ω |Γ |Σ` e i I γi : τi.By (t-fapp) Ω |Γ |Σ` fn (xi : τi){e}(e i I γi) : τ′.Finally, by (t-coerce) Ω |Γ |Σ` (fn (xi : τi){e}(e i I γi))I γR : τ as required.• Case (e-fapp3):136Suppose Ω |Γ |Σ` e(e i) :σ and Ω |Γ |Σ`µ and〈µ, e(e i)〉 Ω−−→〈µ′, e′(e i)〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.From lemma A.1 we get Ω |Γ |Σ` e : fn(τi)→ τ and Ω |Γ |Σ` e i : τi and σ= τfor some τ and τi.By ind. hyp. Ω |Γ |Σ′ ` e′ : fn(τi)→ τ and Ω |Γ |Σ′ `µ′ for some Σ′ ⊇Σ.Then, by lemma A.5 and (t-fapp) Ω |Γ |Σ′ ` e′(e i) : τ as required.• Case (e-fapp4):Suppose Ω |Γ |Σ` fn (xi : τi){e1}(vm, e, en) :σ and Ω |Γ |Σ`µ and〈µ, fn (xi : τi){e1}(vm, e, en)〉 Ω−−→〈µ′, fn (xi : τi){e1}(vm, e′, en)〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.By lemma A.1 Ω |Γ |Σ` fn (xi : τi){e1} : fn(τi)→ τ1 and Ω |Γ |Σ` e i : τi and σ= τ1for some τ1 where xi = xm, x, xn and τi = τm,τ,τn and e i = vm, e, en.By ind. hyp. Ω |Γ |Σ′ ` e′ : τ and Ω |Γ |Σ′ `µ′ for some Σ′ ⊇Σ.Then, by lemma A.5 and (t-fapp) Ω |Γ |Σ′ ` fn (xi : τi){e1}(vm, e′, en) : τ1 as required.• Case (e-seq1):Suppose Ω |Γ |Σ` v; e2 :σ and Ω |Γ |Σ`µ and〈µ,v; e2〉 Ω−−→〈µ, e2〉.By lemma A.1 there are some types τ1,τ2 such thatΩ |Γ |Σ` v : τ1 and Ω |Γ |Σ` e2 : τ2 and σ= τ2 as required.• Case (e-seq2):Suppose Ω |Γ |Σ` e; e2 :σ and Ω |Γ |Σ`µ and〈µ, e; e2〉 Ω−−→〈µ′, e′; e2〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.By lemma A.1 there are some types τ1,τ2 such thatΩ |Γ |Σ` e : τ1 and Ω |Γ |Σ` e2 : τ2.By ind. hyp. Ω |Γ |Σ′ ` e′ : τ1 and Ω |Γ |Σ′ `µ′ for some Σ′ ⊇Σ.Then, by lemma A.5 and t-seq, Ω |Γ |Σ′ ` e′; e2 : τ2 as required.• Case (e-proj1):Suppose Ω |Γ |Σ` S 〈u j〉 {xi : vi}.x :σ and Ω |Γ |Σ`µ and〈µ,S 〈u j〉 {xi : vi}.x〉 Ω−−→〈µ,v〉where (x : v) ∈ xi : vi.137From lemma A.1 we know that there are some X j,σi,σ′ such thatΩ |Γ |Σ` S 〈u j〉 {xi : vi} : S 〈u j〉 and S 〈X j〉 {xi :σi} ∈Ωwhere (x :σ′) ∈ xi :σi and σ= [u j/X j]σ′.Using lemma A.1 again we get Ω |Γ |Σ` vi : [u j/X j]σiso Ω |Γ |Σ` v : [u j/X j]σ′ as required.• Case (e-proj2):Suppose Ω |Γ |Σ` (S 〈u j〉 {xi : vi}I γ).x :σ and Ω |Γ |Σ`µ and〈µ, (S 〈u j〉 {xi : vi}I γ).x〉 Ω−−→〈µ,S 〈u′j〉 {xi : vi II [γ j/X j]σi}.x〉where γ j = spar ( j,γ)and S 〈X j〉 {xi :σi} ∈Ωand Ω` γ : S 〈u j〉 ∼ S 〈u′j〉.From lemma A.1 we know that for some σ′:Ω |Γ |Σ` S 〈u j〉 {xi : vi} : S 〈u j〉 andΩ |Γ |Σ` vi : [u j/X j]σiiandΩ |Γ |Σ` S 〈u j〉 {xi : vi}I γ : S 〈u′j〉 and(x :σ′) ∈ xi :σi andσ= [u′j/X j]σ′.By (co-spar), Ω` γ j : u j ∼ u′j.By lemma A.13 and rule (t-coerce), Ω |Γ |Σ` vi I [γ j/X j]σi : [u′j/X j]σii.Then by (new-struct) Ω |Γ |Σ` S 〈u′j〉 {xi : vi I [γ j/X j]σi} : S 〈u′j〉and by (t-proj) Ω |Γ |Σ` S 〈u′j〉 {xi : vi I [γ j/X j]σi}.x : [u′j/X j]σ′ as required.• Case (e-proj3):Suppose Ω |Γ |Σ` e.x :σ and Ω |Γ |Σ`µ and〈µ, e.x〉 Ω−−→〈µ, e′.x〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.From lemma A.1 we know that there are some S,u j, X j,σi,σ′ such thatΩ |Γ |Σ` e : S 〈u j〉 and S 〈X j〉 {xi :σi} ∈Ωand (x :σ′) ∈ xi :σi and σ= [u j/X j]σ′.By ind. hyp. there is some Σ′ ⊇Σ whereΩ |Γ |Σ′ `µ and Ω |Γ |Σ′ ` e′ : S 〈u j〉.Then we can apply rule (t-proj) to get Ω |Γ |Σ′ ` e′.x : [u j/X j]σ′ as required.• Case (e-struct):138Suppose Ω |Γ |Σ` S 〈u j〉 {xm : vn, x : e, xn : en} :σ and Ω |Γ |Σ`µ and〈µ,S 〈u j〉 {xm : vn, x : e, xn : en}〉 Ω−−→〈µ′,S 〈u j〉 {xm : vn, x : e′, xn : en}〉where 〈µ, e〉 Ω−−→〈µ, e′〉.Let xi = xm, x, xn and e i = vm, e, en.Fromm lemma A.1 we know that there are some X j,σi such that:S 〈X j〉 {xi :σi} ∈Ωand Ω |Γ |Σ` e i : [u j/X j]σi and σ= S 〈u j〉.Then, as there is some σ′ where (x :σ′) ∈ xi :σi we have Ω |Γ |Σ` e : [u j/X j]σ′.By ind. hyp. there is some Σ′ ⊇Σ whereΩ |Γ |Σ′ `µ and Ω |Γ |Σ′ ` e′ : [u j/X j]σ′.We can then apply rule (t-newstruct) to getΩ |Γ |Σ` S 〈u j〉 {xm : vn, x : e′, xn : en} : S 〈u j〉as required.• Case (e-tapp1):Suppose Ω |Γ |Σ` (ΛX i.e)[ui] :σ and Ω |Γ |Σ`µ and〈µ, (ΛX i.e)[ui]〉 Ω−−→〈µ, [ui/X i]e〉.From lemma A.1 we know that there is some σ′ such thatΩ |Γ |Σ`ΛX i..e :∀X i.σ′ and σ= [ui/X i]σ′.Using lemma A.1 again we get Ω |Γ, X i |Σ` e :σ′ with X i 6∈ FV (Ω,Γ,Σ).We can then use lemma A.9 to get Ω |Γ |Σ` e : [ui/X i]σ′ as required.• Case (e-tapp2):Suppose Ω |Γ |Σ` ((ΛX i.e)I γ)[ui] and Ω |Γ |Σ`µ and〈µ, ((ΛX i.e)I γ)[ui]〉 Ω−−→〈µ, [ui/X i]eI γ[ui]〉.From lemma A.1 we get:Ω |Γ |Σ` (ΛX i.e)I γ :∀X i.σ′ andΩ` γ :∀X i.σ′′ ∼∀X i.σ′ andΩ |Γ |Σ`ΛX i.e :∀X i.σ′′ andΩ |Γ, X i |Σ` e :σ′′ with X i 6∈ FV (Ω,Γ,Σ) andσ= [ui/X i]σ′for some σ′,σ′′.Using lemma A.9 we get Ω |Γ |Σ` [ui/X i]e :σ′′.From (co-tapp) we get Ω` γ[ui] : [ui/X i]σ′′ ∼ [ui/X i]σ′.Then using (t-coerce) we get Ω |Γ |Σ` [ui/X i]eI γ[ui] : [ui/X i]σ′ as required.139• Case (e-tapp3):Suppose Ω |Γ |Σ` e[ui] :σ and Ω |Γ |Σ`µ and〈µ, e[ui]〉 Ω−−→〈µ′, e′[ui]〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.From lemma A.1 we know that there are some X i,ω j,σ′ such thatΩ |Γ |Σ` e :∀X i.σ′ and σ= [ui/X i]σ′.From ind. hyp. we get Ω |Γ |Σ′ ` e′ :∀X i.τ and Ω |Γ |Σ′ `µ′ for some Σ′ ⊇Σ.Then, using rule (t-tapp) we get Ω |Γ |Σ` e′[ui] : [ui/X i]σ′ as required.• Case (e-capp1):Suppose Ω |Γ |Σ` (Λci :ωi.e)JγiK :σ and Ω |Γ |Σ`µ and〈µ, (Λci :ωi.e)JγiK〉 Ω−−→〈µ, [γi/ci]e〉.From lemma A.1 we know thatΩ |Γ |Σ`Λci :ωi.e :∀ωi.σ and Ω` γi :ωi.Using lemma A.1 again we get Ω, ci :ωi |Γ |Σ` e :σ.Then lemma A.11 gives us Ω |Γ |Σ` [γi/ci]e :σ as required.• Case (e-capp2):Suppose Ω |Γ |Σ` ((Λci :ωi.e)I γ)JγiK :σ and Ω |Γ |Σ`µ and〈µ, ((Λci :ωi.e)I γ)JγiK〉 Ω−−→〈µ, [γ′i/ci]eI γ′〉where γ′i = coer-l (i,γ)◦γi ◦ sym (coer-r (i,γ)) and γ′ = coer γ.From lemma A.1 we get: Ω |Γ |Σ` (Λci :ωi.e)I γ :∀ω′i.σ andΩ` γi :ω′i andΩ` γ :∀ωi.σ′ ∼∀ω′i.σ andΩ |Γ |Σ`Λci :ωi.e :∀ωi.σ′ andΩ, ci :ωi |Γ |Σ` e :σ′.Let ωi = u1 i ∼ u2 i and ω′i = u′1 i ∼ u′2 i.Using (co-coer-l) we get Ω` coer-l (i,γ) : u1 i ∼ u′1 i.Using (co-coer-r) and (co-sym) we get Ω` sym (coer-r (i,γ)) : u′2 i ∼ u2 i.Using (co-trans) twice we get Ω` coer-l (i,γ)◦γi ◦ sym (coer-r (i,γ)) : u1 i ∼ u2 i.Using (co-coer) we get Ω` coer γ :σ′ ∼σ.From lemma A.11 we get Ω |Γ |Σ` [γ′i/ci]e :σ′and using (t-coerce) we get Ω |Γ |Σ` [γ′i/ci]e :σ as required.140• Case (e-capp3):Suppose Ω |Γ |Σ` eJγiK :σ and Ω |Γ |Σ`µ and〈µ, eJγiK〉 Ω−−→〈µ′, e′JγiK〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.From lemma A.1 we know that Ω |Γ |Σ` e :∀ωi.σ and Ω` γi :ωi for some ci,ωi.By ind. hyp. there is some Σ′ ⊇Σ where Ω |Γ |Σ′ ` e′ :∀ωi.σ and Ω |Γ |Σ′ `µ′.Then we can use rule (t-capp) to prove Ω |Γ |Σ` e′JγiK :σ as required.• Case (e-pack):Suppose Ω |Γ |Σ` pack (τ1,vm, e, en,γ j) as τ2 :σ and Ω |Γ |Σ`µ and〈µ,pack (τ1,vm, e, en,γ j) as τ2〉 Ω−−→〈µ′,pack (τ1,vm, e′, en,γ j) as τ2〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.Let e i = vm, e, en.From lemma A.1 we know that there are some T,τi,ω j such thatΩ |Γ |Σ` e i : [τ1/T]τi and Ω` γ j : [τ1/T]ω j and σ= τ2 =&(∃T,τi,ω j).So, there is some τ ∈ τi such that Ω |Γ |Σ` e : [τ1/T]τ.By ind. hyp. there is some Σ′ ⊇Σ where Ω |Γ |Σ′ ` e′ : [τ1/T]τ and Ω |Γ |Σ′ `µ′.We can then use rule (t-pack) with lemma A.5 to proveΩ |Γ |Σ′ ` pack (τ,vi,γ j) as τ2 :&(∃T,τi,ω j) as required.• Case (e-unpack1):Suppose Ω |Γ |Σ` let (T, xi)= unpack (pack (τ1,vi,γ j) as τ2) in e :σ and Ω |Γ |Σ`µ and〈µ, let (T, xi)= unpack (pack (τ1,vi,γ j) as τ2) in e〉 Ω−−→〈µi, [l i/xi][τ1/T]e〉where µ0 =µ and 〈µi, l i〉 = alloc(µi−1,vi) and l i 6∈ dom(µ).Lemma A.1 tells us that there are some τ,τi,ω j such that:Ω |Γ |Σ` pack (τ1,vi,γ j) as τ2 :&(∃T,τi,ω j) andΩ |Γ,T, xi : τi |Σ` e : τ with T 6∈ FV (Ω,Γ,Σ,τ) andΩ |Γ |Σ` vi : [τ1/T]τi andσ= τ.Lemma A.12 tells us that there is a store typing Σ′ ⊇Σ such thatΩ |Γ |Σ′ `µi and Ω |Γ |Σ′ ` l i : [τ1/T]τi.We can use lemma A.9 to get Ω |Γ, xi : [τ1/T]τi |Σ` [τ1/T]e : [τ1/T]τ.As T 6∈ FV (τ), we know that [τ1/T]τ= τ.We can then use lemma A.6 and A.5 to get Ω |Γ |Σ′ ` [l i/xi][τ1/T]e : τ. as required.141• Case (e-unpack2):Suppose Ω |Γ |Σ` let (T, xi)= unpack ((pack (τ1,vi,γ j) as &(∃T,τ′i,ω′j))I γ) in e :σ andΩ |Γ |Σ`µ and〈µ, let (T, xi)= unpack ((pack (τ1,vi,γ j) as &(∃T,τ′i,ω′j))I γ) in e〉Ω−−→〈µ, let (T, xi)= unpack (pack (τ1,vi I γi,γ′j) as &(∃T,τi,ω j)) in e〉where Ω` γ :&(∃T,τ′i,ω′j)∼&(∃T,τi,ω j) andγi = objf (τ1, i,∗γ) and γ′j = (sym (objc-l (τ1, j,∗γ)))◦γ j ◦objc-r (τ1, j,∗γ)j.Lemma A.1 tells us that:Ω |Γ |Σ` (pack (τ1,vi,γ j) as &(∃T,τ′i,ω′j))I γ :&(∃T,τi,ω j) andΩ |Γ,T, xi : τi |Σ` e : τ with T 6∈ FV (Ω,Γ,Σ,τ) andΩ |Γ |Σ` pack (τ,vi,γ j) as &(∃T,τ′i,ω′j) :&(∃T,τ′i,ω′j) andΩ` γ j : [τ1/T]ω′j andΩ |Γ |Σ` vi : [τ1/T]τ′i andσ= τ for some τ.Let ω j = u1 j ∼ u3 j and ω′j = u2 j ∼ u4 j.By applying rule (co-deref) and (co-objf) we get Ω` γi : [τ1/T]τ′i ∼ [τ1/T]τi.We can show that Ω` γ′j : [τ1/T]ω j with the following derivation:(co-comp)Ω` sym (objc-l (τ1, j,∗γ)) : [τ1/T]u1 j ∼ [τ1/T]u2 jΩ` γ j ◦objc-r (τ1, j,∗γ) : [τ1/T]u2 j ∼ [τ1/T]u3 jΩ` (sym (objc-l (τ1, j,∗γ)))◦γ j ◦objc-r (τ1, j,∗γ) : [τ1/T]u1 j ∼ [τ1/T]u3 jwhere(co-sym)(co-objf)(co-deref)Ω` γ :&(∃T,τ′i,ω′j))∼&(∃T,τi,ω j)Ω`∗γ : (∃T,τ′i,ω′j))∼ (∃T,τi,ω j)Ω` objc-l (τ1, j,∗γ) : [τ1/T]u2 j ∼ [τ1/T]u1 jΩ` sym (objc-l (τ1, j,∗γ)) : [τ1/T]u1 j ∼ [τ1/T]u2 jand(co-comp)Ω` γ j : [τ1/T]u2 j ∼ [τ1/T]u4 j(co-objc-r)Ω` γ :&(∃T,τ′i,ω′j))∼&(∃T,τi,ω j)Ω`∗γ : (∃T,τ′i,ω′j))∼ (∃T,τi,ω j)objc-r (τ1, j,∗γ) : [τ1/T]u4 j ∼ [τ1/T]u3 jΩ` γ j ◦objc-r (τ1, j,∗γ) : [τ1/T]u2 j ∼ [τ1/T]u3 jWe can use rule (t-coerce) to prove Ω |Γ |Σ` vi I γi : [τ1/T]τiand then rule (t-pack) to proveΩ |Γ |Σ` pack (τ1,vi I γi,γ′j) as &(∃T,τi,ω j) :&(∃T,τi,ω j).Finally we can use (t-unpack) to proveΩ |Γ |Σ` let (T, xi)= unpack (pack (τ1,vi I γi,γ′j) as &(∃T,τi,ω j)) in e : τ as required.142• Case (e-unpack3):Suppose Ω |Γ |Σ` let (T, xi)= unpack e in e2 :σ and Ω |Γ |Σ`µ and〈µ, let (T, xi)= unpack e in e2〉 Ω−−→〈µ′, let (T, xi)= unpack e′ in e2〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.Lemma A.1 tells us that there are some τ,τi,ω j such that:Ω |Γ |Σ` e :&(∃T,τi,ω j) andΩ |Γ,T, xi : τi |Σ` e2 : τ with T 6∈ FV (Ω,Γ,Σ,τ) and σ= τ.From ind. hyp. we get some Σ′ ⊇Σ whereΩ |Γ |Σ′ ` e′ :&(∃T,τi,ω j) andΩ |Γ |Σ′ `µ′.Then by (t-unpack) and lemma A.5 we get Ω | Γ | Σ′ ` let (T, xi) = unpack e′ in e2 : τ asrequired.• Case (e-coerce1):Suppose Ω |Γ |Σ` (pvI γ1)I γ2 :σ and Ω |Γ |Σ`µ and〈µ, (pvI γ1)I γ2〉 Ω−−→〈µ, pvI (γ1 ◦γ2)〉.From lemma A.1 we get Ω` γ2 :σ′ ∼σ andΩ |Γ |Σ` pvI γ1 :σ′ andΩ` γ1 :σ′′ ∼σ′ andΩ |Γ |Σ` pv :σ′′for some σ′,σ′′.By (co-trans) Ω` γ1 ◦γ2 :σ′′ ∼σand by (t-coerce) Ω |Γ |Σ` pvI (γ1 ◦γ2) :σ as required.• Case (e-coerce2):Suppose Ω |Γ |Σ` eI γ :σ and Ω |Γ |Σ`µ and〈µ, eI γ〉 Ω−−→〈µ′, e′I γ〉.From lemma A.1 we get Ω` γ :σ′ ∼σ and Ω |Γ |Σ` e :σ′ for some σ′.From ind. hyp. we get some Σ′ ⊇Σ whereΩ |Γ |Σ′ ` e′ :σ′ andΩ |Γ |Σ′ `µ′.Then by (t-coerce) Ω |Γ |Σ′ ` e′I γ :σ as required.• Case (el-deref1):Suppose Ω |Γ |Σ`∗e : τ and Ω |Γ |Σ`µ and 〈µ,∗e〉 lv(Ω)−−−→〈µ′,∗e′〉where 〈µ, e〉 Ω−−→〈µ′, e′〉.143From lemma A.1 we get Ω |Γ |Σ` e :&τ.From ind. hyp. we get some Σ′ ⊇Σ whereΩ |Γ |Σ′ ` e′ :&τ andΩ |Γ |Σ′ `µ′.Then by (t-deref) Ω |Γ |Σ′ `∗e′ : τ as required.• Case (el-deref2):Suppose Ω |Γ |Σ`∗&l : τ and Ω |Γ |Σ`µ and 〈µ,∗&l〉 lv(Ω)−−−→〈µ′, l〉.From lemma A.1 we get Ω |Γ |Σ`&l :&τ and Ω |Γ |Σ` l : τ as required.• Case (el-deref3):Suppose Ω |Γ |Σ`∗(&lI γ) : τ and Ω |Γ |Σ`µ and 〈µ,∗(&lI γ)〉 lv(Ω)−−−→〈µ′, lI∗γ〉.From lemma A.1 we get Ω |Γ |Σ`&lI γ :&τ andΩ` γ :&τ′ ∼&τ andΩ |Γ |Σ`&l :&τ′ andΩ |Γ |Σ` l : τ′ for some τ′.By (co-deref) Ω`∗γ : τ′ ∼ τ andby (t-coerce) Ω` lI∗γ : τ as required.• Case (el-proj1):Suppose Ω |Γ |Σ` lv.x : τ and Ω |Γ |Σ`µ and 〈µ, lv.x〉 lv(Ω)−−−→〈µ′, lv′.x〉where 〈µ, lv〉 lv(Ω)−−−→〈µ, lv′〉.From lemma A.1 we get Ω |Γ |Σ` lv : S 〈u j〉 andS 〈X j〉 {xm :σm, x : τ′, xn :σn} ∈Ω andτ= [u j/X j]τ′for some S,u j, X j, xm, xn,σm,σn,τ′.From ind. hyp. we get some Σ′ ⊇Σ whereΩ |Γ |Σ′ ` lv′ : S 〈u j〉 andΩ |Γ |Σ′ `µ′.Then by (t-proj) Ω |Γ |Σ′ ` lv′.x : [u j/X j]τ′ as required.• Case (el-proj2):Suppose Ω |Γ |Σ` l.x : τ and Ω |Γ |Σ`µ and 〈µ, l.x〉 lv(Ω)−−−→〈µ, l′〉where µ(l)= S 〈u j〉 {xm : lm, x : l′, xn : ln}.From the definition of Ω |Γ |Σ`µ we getΩ |Γ |Σ`µ(l) :σ and Ω |Γ |Σ` l :σ for some σ.144From lemma A.1 we getS 〈X j〉 {xm :σm, x : τ′, xn :σn} ∈Ω andΩ |Γ |Σ` S 〈u j〉 {xm : lm, x : l′, xn : ln} : S 〈u j〉 andΩ |Γ |Σ` l′ : [u j/X j]τ′ andσ= S 〈u j〉 and for some X j,σm,σn,τ′.From (t-proj) we get Ω |Γ |Σ` l.x : [u j/X j]τ′ as required.• Case (el-proj3):Suppose Ω |Γ |Σ` l.x : τ and Ω |Γ |Σ`µ and 〈µ, l.x〉 lv(Ω)−−−→〈µ, l′I [γ j/X j]τ′〉where µ(l)= S 〈u j〉 {xm : lm, x : l′, xn : ln}I γ andS 〈X j〉 {xm :σm, x : τ′, xn :σn} ∈Ω andγ j = spar ( j,γ).From Ω |Γ |Σ`µ we get Ω |Γ |Σ`µ(l) :σ and Ω |Γ |Σ` l :σ for some σ.From lemma A.1 we getΩ |Γ |Σ` S 〈u j〉 {xm : lm, x : l′, xn : ln} : S 〈u j〉 andΩ |Γ |Σ` γ : S 〈u j〉 ∼σ andΩ |Γ |Σ` l′ : [u j/X j]τ′.Combining lemma A.1 with consistency of Ω we get σ= S 〈u′j〉 for some u′j.Ω |Γ |Σ`µ(l) : S 〈u′j〉.By (t-proj) Ω |Γ |Σ` l.x : [u′j/X j]τ′.By (co-spar) Ω` γ j : u j ∼ u′j.By lemma A.13 Ω` [γ j/X ]τ′ : [u j/X j]τ′ ∼ [u′j/X j]τ′ andby (t-coerce) Ω |Γ |Σ` l′I [γ j/X ]τ′ : [u′j/X j]τ′ as required.• Case (el-proj4):Suppose Ω |Γ |Σ` (lI γ).x : τ and Ω |Γ |Σ`µ and 〈µ, (lI γ).x〉 lv(Ω)−−−→〈µ, l′I [γ j/X j]τ′〉where µ(l)= S 〈u j〉 {xm : lm, x : l′, xn : ln} andS 〈X j〉 {xm :σm, x : τ′, xn :σn} ∈Ω andγ j = spar ( j,γ).From Ω |Γ |Σ`µ we get Ω |Γ |Σ`µ(l) :σ and Ω |Γ |Σ` l :σ for some σ.From lemma A.1 we getΩ |Γ |Σ`µ(l) : S 〈u j〉 and σ= S 〈u j〉, andΩ |Γ |Σ` l′ : [u j/X j]τ′.Combining lemma A.1 with consistency of Ω we getΩ` γ : S 〈u j〉 ∼ S 〈u′j〉 andΩ |Γ |Σ` lI γ : S 〈u′j〉 and145Ω |Γ |Σ` (lI γ).x : [u′j/X j]τ′for some u′j.By (co-spar) Γ` γ j : u j ∼ u′j.By lemma A.13 Ω` [γ j/X j]τ′ : [u j/X j]τ′ ∼ [u′j/X j]τ′.By (t-coerce) Ω |Γ |Σ` l′I [γ j/X j]τ′ : [u′j/X j]τ′ as required.• Case (el-proj5):Suppose Ω |Γ |Σ` (lI γ1).x : τ and Ω |Γ |Σ`µ and〈µ, (lI γ1).x〉 lv(Ω)−−−→〈µ, l′I [γ j/X j]τ′〉where µ(l)= S 〈u j〉 {xm : lm, x : l′, xn : ln}I γ2 andS 〈X j〉 {xm :σm, x : τ′, xn :σn} ∈Ω andγ j = spar ( j,γ2 ◦γ1).From Ω |Γ |Σ`µ we get Ω |Γ |Σ`µ(l) :σ and Ω |Γ |Σ` l :σ for some σ.From lemma A.1 and corollary A.1we getΩ |Γ |Σ` γ2 : S 〈u j〉 ∼ τ′′ andΩ |Γ |Σ` S 〈u j〉 {xm : lm, x : l′, xn : ln} : S 〈u j〉 andΩ |Γ |Σ` l′ : [u j/X j]τ′.Then, using lemma A.1 again we get Ω` γ1 : τ′′ ∼σ′where σ′ is a type of the form S′ 〈uk〉 for some S′,uk.By (co-trans) Ω` γ2 ◦γ1 : S 〈u j〉 ∼σ′and from consistency of Ω′ it follows that σ′ = S 〈u′j〉 for some u′j.By (t-coerce) Ω |Γ |Σ` l : τ′′ and Ω |Γ |Σ` lI γ1 : S 〈u′j〉.By (t-proj) Ω |Γ |Σ` (lI γ1).x : [u′j/X j]τ′.By (co-spar) Ω` γ j : u j ∼ u′j.Then by lemma A.13 Ω` [γ j/X ]τ′ : [u j/X j]τ′ ∼ [u′j/X j]τ′ andby (t-coerce) Ω |Γ |Σ` l′I [γ j/X ]τ′ : [u′j/X j]τ′ as required.Theorem 6.2 (Progress). Suppose Ω is a consistent environment.1. If Ω | ; | Σ ` e : σ then either e ∈ VAL or, for any store µ such that Ω | ; | Σ ` µ, there issome term e′ and store µ′ with 〈µ, e〉 Ω−−→〈µ′, e′〉2. If Ω | ; |Σ` lv : τ then either lv ∈CLOC or, for any store µ such that Ω | ; |Σ`µ, there issome lvalue lv′ and store µ′ with 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉146Proof. By simultaneous induction on derivations Ω | ; |Σ` e :σ assuming Ω | ; |Σ` µ in allcases:• Case (t-let):Ω | ; |Σ` let x : τ1 = e1 in e2 : τ2 andΩ | ; |Σ` e1 : τ1 andΩ | x : τ1 |Σ` e2 : τ2.We consider two cases for e1:– Case e1 = v:We can take a step using (e-let1).– Case e1 6∈VAL:From ind. hyp. we know that there are some e′1,µ′ such that 〈µ, e1〉 Ω−−→〈µ′, e′1〉We can then take a step using (e-let2).• Case (t-upd):Ω | ; |Σ` lv := e : () andΩ | ; |Σ` lv : τ andΩ | ; |Σ` e : τ.We consider the following cases for lv and e:– Case lv= l and e 6∈VAL:From ind. hyp. we know that there are some e′,µ′ such that 〈µ, e〉 Ω−−→〈µ′, e′〉We can then take a step with rule (e-upd4).– Case lv= l and e= v:We can take a step with rule (e-upd2).– Case lv= lI γ:We can take a step with rule (e-upd3).– Case lv 6∈CLOC:From ind. hyp. we know that there are some lv′,µ′ such that〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉.We can then use (e-upd1) to take a step.• Case (t-fapp) :Suppose Ω | ; |Σ` e(e i) : τ andΩ | ; |Σ` e : fn(τi)→ τ andΩ | ; |Σ` e i : τi.147From lemma A.2 we know that if v ∈VAL then eitherv= fn (xi : τi){e1} orv= fn (xi : τ′i){e1}I γfor some xi,τ′i, e1,γ.We consider the following cases for e and e i:– Case e= fn (xi : τi){e1} and e i ∈VAL:We can use rule (e-fapp1) to take a step.– Case e= fn (xi : τi){e1} where there is a term e′ ∈ e i that is not a value:Let e i = v j, e′, ek and τi = τ j,τ′,τk.Then, since Ω | ; |Σ` e′ : τ′, from ind. hyp. we get〈µ, e′〉 Ω−−→〈µ′, e′′〉 and µ′, e′′.We can then use rule (e-fapp4) to take a step.– Case e= fn (xi : τ′i){e1}I γ:We can use rule (e-fapp2) to take a step.– Case e 6∈VAL:From ind. hyp. we get 〈µ, e〉 Ω−−→〈µ′, e′〉for some e′,µ′ and Σ′ ⊇Σ.Then we can take a step using (e-fapp3).• Case (t-fabs) :Ω |Γ |Σ` fn (xi : τi){e} : fn(τi)→ τfn (xi : τi){e} ∈VAL as required.• Case (t-ref) :Ω | ; |Σ`&lv :&τ andΩ | ; |Σ` lv : τ.– Case lv= l :&l ∈VAL.– Case lv= lI γ:We can take a step with (e-ref2).– Case lv 6∈CLOC:From ind. hyp. we know that there some µ′, lv′ where 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉.We can then use rule (e-ref1) to take a step.148• Case (t-deref):Ω | ; |Σ`∗e : τ andΩ | ; |Σ` e :&τ.If e ∈VAL then by lemma A.2, either e=&l for some l or e=&lI γ for some l and γ.We then consider the following cases for e, proving both points 1. and 2. as ∗e is anlvalue:– Case e=&l :1. We can use rule (e-deref1) to take a step.2. We can take a step with (el-deref2).– Case e=&lI γ :1. We can use rule (e-deref2) to take a step.2. We can take a step with (el-deref3).– Case e 6∈VAL :From ind. hyp. we know that there are some µ′, e′ such that〈µ, e〉 Ω−−→〈µ′, e′〉.Then:1. We can take a step with (e-deref3).2. We can take a step with (e-deref1).• Case (t-var):Ω | ; |Σ` x :σ and(x :σ) ∈;.Vacuous as (x :σ) ∈; is impossible.• Case (t-loc):Suppose Ω | ; |Σ` l :σ and ΓT |Σ`µ.l ∈ LVAL so we must show the case holds for both cases:1. We can take a step with (e-loc) as by lemma A.16 the call to getValue will succeed.2. l ∈CLOC as required.From lemma A.1 we know Σ(l)=σ.• Case (t-unit):Ω | ; |Σ` () : ()() ∈VAL as required.149• Case (t-seq):Ω | ; |Σ` e1; e2 : τ2 and Ω | ; |Σ` e1 : τ1 and Ω | ; |Σ` e2 : τ2.We consider two cases of e1:– Case e1 = v:We can use (e-seq1) to take a step.– Case e1 6∈VAL:From ind. hyp. we know that there are some µ′, e′1 such that〈µ, e1〉 Ω−−→〈µ′, e′1〉.We can then make a step using rule (e-seq2).• Case (t-newstruct):Ω | ; |Σ` S 〈u j〉 {xi : e i} : S 〈u j〉 andS 〈X j〉 {xi :σi} ∈Ω andΩ | ; |Σ` e i : [u j/X j]σi.We consider two cases of e i:– Case e i = vi:Then S 〈u j〉 {xi : vi} ∈VAL.– Case e i = vm, e, en where e 6∈VAL:Let xi = xm, x, xn and σi =σm,σ,σn.From ind. hyp. we know there are some µ′, e′1 such that〈µ, e1〉 Ω−−→〈µ′, e′1〉.We can then use rule (e-struct) to take a step as required.• Case (t-proj) :Ω | ; |Σ` e.x : [u j/X j]σ andΩ | ; |Σ` e : S 〈u j〉 andS 〈X j〉 {xi :σi} ∈Ωwhere (x :σ) ∈ xi :σi.Since e.x can be an lvalue, we must prove that both statements of the lemma hold.1. If e ∈VAL then from lemma A.2 we know that eithere= S 〈u j〉 {xi : vi} for some xi,vi ore= S 〈u′j〉 {xi : vi}I γ for some u′j, xi,vi and γ where ΓT |Σ` γ : S 〈u′j〉 ∼ S 〈u j〉.We then proceed by cases on e:150– Case e= S 〈u j〉 {xi : vi}:We can take a step with (e-proj1).– Case e= S 〈u′j〉 {xi : vi}I γ:We can take a step with (e-proj2).– Case e 6∈VAL:Using ind. hyp. we know that there are some µ′, e′ such that〈µ, e〉 Ω−−→〈µ′, e′〉.We can then take a step using rule (e-proj3).2. Suppose e= lv and σ= τ for some lv and τ.We then proceed by cases on lv:– lv= l:From Ω | ; |Σ`µ it follows that Ω | ; |Σ`µ(l) : S 〈u j〉.From lemma A.3 we know that eitherµ(l)= S 〈u j〉 {xi : l i} for some l i orµ(l)= S 〈u′j〉 {xi : l i}I γ for some u′j, l i,γ where Ω` γ : S 〈u′j〉 ∼ S 〈u j〉.In the first case we can take a step with (el-proj2)and in the second case we can take a step with (el-proj3).– lv= lI γ:We know that Ω | ; |Σ` lI γ : S 〈u j〉.From lemma A.1 and corollary A.1 we know that there is some τ′ such thatΩ` γ : τ′ ∼ S 〈u j〉 andΩ | ; |Σ` l : τ′.From Ω | ; |Σ`µ it follows that Ω | ; |Σ`µ(l) : τ′.From lemma A.3 we know that eitherµ(l)= S 〈u′j〉 {xi : l i} where τ′ = S 〈u′j〉 for some l i,u′j orµ(l)= S 〈u′j〉 {xi : l i}I γ′ for some u′j, l i,γ where Ω` γ′ : S 〈u′j〉 ∼ τ′.In the first case we can take a step with (el-proj4)and in the second case we can take a step with (el-proj5).– lv 6∈CLOC:By ind. hyp. there are some lv′,µ′ where 〈µ, lv〉 lv(Ω)−−−→〈µ′, lv′〉.We can then take a step with (el-proj1) as required.• Case (t-unpack):151Ω | ; |Σ` let (T, xi)= unpack e1 in e2 : τ andΩ | ; |Σ` e1 :&(∃T,τi,ω j) andΩ | T, xi : τi |Σ` e2 : τ.From lemma A.2 we know that if e1 is a value then eithere1 = pack (τ,vi,γ j) as &(∃T,τi,ω j), ore1 = (pack (τ,vi,γ j) as &(∃T,τ′i,ω′j))I γ for some τ′i,ω′j where Γ | Σ ` γ : &(∃T,τ′i,ω′j)) ∼&(∃T,τi,ω j).We proceed by cases of e1:– e1 = pack (τ,vi,γ j) as &(∃T,τi,ω j):We can take a step with (e-unpack1).– e1 = (pack (τ,vi,γ j) as &(∃T,τ′i,ω′j))I γ:We can take a step with (e-unpack2).– e1 6∈VAL:By the ind. hyp. there are µ′, e′1 such that 〈µ, e1〉Ω−−→〈µ′, e′1〉.We can then take a step using (e-unpack3) as required.• Case (t-pack):ΓT |Σ` pack (τ, e i,γ j) as &(∃T,τi,ω j) :&(∃T,τi,ω j) andΩ | ; |Σ` e i : [τ/T]τi andΩ` γ j : [τ/T]ω j.We proceed by cases of e i:– Case e i = vi:(pack (τ,vi,γ j) as &(∃T,τi,ω j)) ∈VAL.– Case e i = vm, e, en where e 6∈VAL:From ind. hyp. there are some µ′, e′ such that〈µ, e〉 Ω−−→〈µ, e′〉.We can then use rule (e-pack) to make a step.• Case (t-tapp) :Ω | ; |Σ` e[ui] : [ui/X i]σ andΩ | ; |Σ` e :∀X i.σ.From lemma A.2 we know that if e ∈VAL then either:e=∀X i.e′ for some e′ ore= (∀X i.e′)I γ for some e′,γ.We proceed by cases of e:152– Case e=∀X i.e′:We can take a step with rule (e-tapp1).– Case e= (∀X i.e′)I γ:We can take a step with rule (e-tapp2).– Case e 6∈VAL:By ind. hyp. there are some e′,µ′ such that〈µ, e〉 Ω−−→〈µ′, e′〉.We can then use rule (e-tapp3) to take a step.• Case (t-tabs) :Ω | ; |Σ`ΛX i.e :∀X i.σ.ΛX i.e ∈VAL.• Case (t-capp) :Ω | ; |Σ` eJγiK :σ andΩ | ; |Σ` e :∀ωi.σ andΩ` γi :ωi.From lemma A.2 we know that if e ∈VAL then either:e=∀ωi.e′ for some e′ ore= (∀ω′i.e′)I γ for some e′,ω′i,γ.We proceed on cases of e:– Case e=∀ωi.e′:We can use rule (e-capp1) to take a step.– Case e= (∀ω′i.e′)I γWe can use rule (e-capp2) to take a step.– Case e 6∈VAL:By ind. hyp. there are some e′,µ′ such that〈µ, e〉 Ω−−→〈µ′, e′〉.Then we can use rule (e-capp3) to take a step.• Case (t-cabs):(Λci :ωi.e) ∈VAL.• Case (t-coerce):153ΓT |Σ` eI γ :σ2 andΓ` γ :σ1 ∼σ2 andΓ |Σ` e :σ1.Since eI γ could be an lvalue, we must show that the case holds for both statements ofthe theorem.1. We proceed by cases of e:– Case e= pv:Then (pvI γ) ∈VAL.– Case e= pvI γ′:Then we can take a step with (e-coerce1).– Case e 6∈VAL:By ind. hyp. there are some e′,µ′ such that〈µ, e〉 Ω−−→〈µ′, e′〉.Then we can use rule (e-coerce2) to take a step.2. If eI γ is an lvalue it must be of the form lI γ for some l.Then lI γ ∈CLOC as required.Theorem 6.3. Suppose ` pgm :Ω |Γ where Ω is consistent and Γ= {xi :σi}.If (main : fn()→ ()) ∈Γ, then there are some µ, e, Σ for which〈pgm〉 Ω−−→〈µ, e〉, and Ω | ; |Σ`µ, and Ω | ; |Σ` e : ().Proof. Wlog, let pgm= {type,axiom,struct,decl} where decl= xi :σi = vi and main ∈ xi.By rule (t-decl), Ω |Γ | ; ` vi :σi.Let µ0 =;. Then by lemma A.12 alloc(µi−1,vi)= 〈µi, l i〉iwhere l i 6∈ dom(µ0) and there is some Σ whereΩ |Γ |Σ`µi and Ω |Γ |Σ` l i :σi.By lemma A.1 (l i :σi) ∈Σ andwe can use rule (t-loc) to conclude Ω | ; |Σ` l i :σi.We can use the program evaluation rule to take a step〈pgm〉 Ω−−→〈[l i/xi]µi, [l i/xi] fmain()〉.Wlog, let µi = {l j : w j}.By definition of substitution, [l i/xi]µi = {l j : [l i/xi]w j}.From Ω |Γ |Σ`µi we get Ω |Γ |Σ` l j :σ j j and Ω |Γ |Σ`µi(l j) :σ j j for some σ j.By lemma A.6 we get Ω | ; |Σ` l j :σ j and Ω | ; |Σ` [l i/xi]µi(l j) :σ jj154so Ω | ; |Σ` [l i/xi]µi.Finally, let lmain = [l i/xi]main.Then Ω | ; |Σ` lmain : fn()→ () by (t-loc) and Ω | ; |Σ` lmain() : () by (t-app) as required.155Appendix BMiniRust translation proofsLemma B.1 (Inversion of well-formed environment rules). Suppose 〈Γ,Θ〉 〈Ωt,Γt〉.1. If X ∈Γ then X ∈Γt.2. If (x :σ) ∈Γ then there is some σt such that (x :σt) ∈Γt and Γ |Θ`WF σ σt.3. If S 〈X j〉 {xi : τi} ∈Γ then there are some τti such thatΓ, X j |Θ`WF τi τti and S 〈X j〉 {xi : τti} ∈Ωt.4. If (D 〈X i〉where pih,Self :βs xs, A :βa xa, f ,obj) ∈Γ thenΓ, X p |Θ,Self : D 〈X i〉 _`WF Self :βs 〈τts,ωs〉s,Γ, X p |Θ,Self : D 〈X i〉 _`WF AD 〈X p〉 :βa 〈τta,ωa〉a,( f :∀X p, Xk.(Self : D 〈X i〉 ,pil)⇒ τ) ∈Γ ,Γ, X p |Θ,Self : D 〈X i〉 _`WF ∀Xk.pil ⇒ τ σt ,{S 〈X p〉 { f :σt, xs : τts, xa : τta}, AD 〈X p〉}⊆Ωtwhere X p =Self, X i for some τts,ωs,τta,ωa, Xk,pil ,τ.5. If (θ 〈x, c〉) ∈Θ then there are some σt and ϑ such that(x :σt) ∈Γt, and (c :ϑ) ∈Ωt and Γ |Θ`WF θ 〈σt,ϑ〉.Proof. Immediate from the well-formed environments judgments with translation.Lemma B.2 (Inversion of struct declaration typing rule).If Γ |Θ` struct S 〈X j〉 {xi : τi} :Γ′ |Θ′ pgmtthen there are some τti where Γ, X j |Θ`WF τi τtii,Γ′ = [S 〈X j〉 {xi : τi}], and Θ′ =;, and pgmt = struct S 〈X j〉 {xi : τti}.Proof. Immediate from the well-typed items relation.Lemma B.3 (Inversion of well-formedness rules).1561. If Γ |Θ`WF X ut then X ∈Γ and ut = X.2. If Γ |Θ`WF fn(τi)→ τ ut thenΓ |Θ`WF τi τti, and Γ |Θ`WF τ τt, and ut = fn(τti)→ τt for some τt, τti.3. If Γ |Θ`WF &u ut then Γ |Θ`WF u ut1 and ut =&ut1 for some ut1.4. If Γ |Θ`WF S 〈ui〉 ut thenΓ |Θ`WF ui uti, and S 〈X i〉 {x j : τ j} ∈Γ, and [ui/X i] defined, and ut = S 〈uti〉for some X i,uti, x j,τ j.5. If Γ |Θ`WF AD 〈u,ui〉 ut thenΓ |Θ u : D 〈ui, A 7→?〉, and Γ |Θ`WF u ut1, andΓ |Θ`WF ui uti, and ut = AD 〈ut1,uti〉for some ut1, uti.6. If Γ |Θ`WF ∃T : D 〈ui,u1 j ∼ u2 j〉 ut thenthere are some AD j,us j,u j,uti,uts j,utj such thatu1 j = AD j 〈T,us j〉, and Γ`D obj-safe, and Γ` SelfU : D 〈ui〉, andΓ |Θ`WF ui uti, and Γ,T |Θ,T : D 〈ui〉 `WF u1 j AD j 〈T,uts j〉,and Γ |Θ`WF u j utj, and ut =(∃T,&τ,SD 〈T,uti〉 , AD j 〈T,uts j〉 ∼ utj)7. If Γ |Θ`WF ∀X i.pi j ⇒ τ σt then X i 6∈Γ and Γ, X i |Θ,pi j `WF pi j 〈τtj,ω j〉jand Γ, X i |Θ,pi j `WF τ τt and σt =∀X i.∀ω j.fn(τtj)→ τt for some τtj,ω j and τt.8. If Γ |Θ`WF ∀X i.pi j ⇒pi 〈σt,ϑ〉 then Γ, X i |Θ,pi j `WF pi j 〈τtj,ω j〉j,Γ, X i |Θ,pi j `WF pi 〈τt,ut1 ∼ ut2〉,σt =∀X i.∀ω j.fn(τtj)→ τt, and ϑ=∀X i.ut1 ∼∀X i.ut2 for some τtj,ω j,ut1,ut2,τt.9. If Γ |Θ`WF u : D 〈ui, A 7→ uA〉 σt,ϑ then there are some ut,uti,utA whereΓ` u : D 〈ui〉, and Γ` AD , andΓ |Θ`WF u ut, and Γ |Θ`WF ui uti, and Γ |Θ`WF uA utA, andσt = SD 〈ut,uti〉, and ϑ= AD 〈ut,uti〉 ∼ utA.10. If Γ |Θ`WF u : D 〈ui, A 7→?〉 σt,ϑ then there are some ut,uti whereΓ` u : D 〈ui〉, and Γ` AD , andΓ |Θ`WF u ut, and Γ |Θ`WF ui uti, andσt = SD 〈ut,uti〉, and ϑ= AD 〈ut,uti〉 ∼ AD 〈ut,uti〉.Proof. Immediate from the well-formedness judgments.157Lemma B.4 (Contraction of the constraint environment I).1. If Γ |Θ,pi′ 〈x, c〉 `WF u ut and Γ |Θpi′ 〈e′t,γ′〉 then Γ |Θ`WF u ut.2. If Γ |Θ,pi′ 〈x, c〉pi 〈et,γ〉 and Γ |Θpi′ 〈e′t,γ′〉 then Γ |Θpi [e′t/x][γ′/c]et.3. If Γ |Θ,pi′ 〈x, c〉 u1 ∼ u2 γ and Γ |Θpi′ 〈e′t,γ′〉 then Γ |Θ u1 ∼ u2 [γ′/c]γ.Proof. By simultaneous induction on derivationsΓ |Θ,pi′ 〈x, c〉 `WF u ut,Γ |Θ,pi′ 〈x, c〉pi 〈et,γ〉 andΓ |Θ,pi′ 〈x, c〉 u1 ∼ u2 γ.In most cases it is a straightforward use of the induction hypothesis and the definition ofsubstitution.We show the proof for the only interesting case:• Case (c-ext): Γ |Θ,pi′ 〈x′, c′〉 [ui/X i]pi 〈x[uti]Jγ jK(etj), c[uti]〉 where(∀X i.pi j ⇒pi 〈x, c〉) ∈ (Θ,pi′ 〈x′, c′〉),Γ |Θ,pi′ 〈x′, c′〉 `WF ui uti andΓ |Θ,pi′ 〈x′, c′〉 [ui/X i]pi j 〈etj,γ j〉.Assume Γ |Θpi′ 〈e′t,γ′〉.If (∀X i.pi j ⇒ pi) ∈ Θ we can assume x 6= x′, c 6= c′ by the bound variable renaming as-sumption.We can use IH to prove Γ |Θ [ui/X i]pi 〈x[uti]J[γ′/c′]γ jK([e′t/x′][γ′/c′]etj), c[uti]〉.Otherwise, (∀X i.pi j ⇒pi 〈x, c〉)= (pi′ 〈x′, c′〉).Then, as ui, X i, etj and γ j are all empty sequences, we need to showΓ |Θpi′ 〈e′t,γ′〉 which holds from the assumption as required.Lemma B.5 (Contraction of the constraint environment II). If Γ |Θ,pi′ 〈x, c〉 `WF θ 〈σt,ϑ〉and Γ |Θpi′ 〈e′t,γ′〉 then Γ |Θ`WF θ 〈σt,ϑ〉.Proof. Straightforward by induction on derivations Γ |Θ,pi′ 〈x, c〉 `WF θ 〈σt,ϑ〉using lemma B.4 and the IH.Lemma B.6 (Contraction of the constraint environment III). If Γ |Θ,pi′ 〈x, c〉 `WF σ σtand Γ |Θpi′ 〈e′t,γ′〉 then Γ |Θ`WF σ σt.158Proof. If σ ∈ STYPE then the proof is immediate from lemma B.4.Otherwise σ=∀X i.pi j ⇒ τ for some X i,pi j,τ.From lemma B.3 we getΓ, X i |Θ,pi′ 〈x, c〉 ,pi j `WF pi j 〈τtj,ω j〉jand Γ, X i |Θ,pi′ 〈x, c〉 ,pi j `WF τ τt and σt =∀X i.∀ω j.fn(τtj)→ τt for some τtj,ω j and τt.By lemmas B.5 and B.4 we haveΓ, X i |Θ,pi j `WF pi j 〈τtj,ω j〉jand Γ, X i |Θ,pi j `WF τ τt.We can then use (wf-tscheme) to prove Γ |Θ`WF σ σt as required.Lemma B.7 (Type substitution I).1. If Γ, X |Θ`WF u′ u′t and [u/X ]Γ | [u/X ]Θ`WF u utthen [u/X ]Γ | [u/X ]Θ`WF [u/X ]u′ [ut/X ]u′t.2. If Γ, X |Θpi 〈et,γ〉 and [u/X ]Γ | [u/X ]Θ`WF u utthen [u/X ]Γ | [u/X ]Θ [u/X ]pi 〈[u/X ]et, [u/X ]γ〉3. If Γ, X |Θ u1 ∼ u2 γ and [u/X ]Γ | [u/X ]Θ`WF u utthen [u/X ]Γ | [u/X ]Θ [u/X ](u1 ∼ u2) [u/X ]γ.Proof. By simultaneous induction on derivationsΓ, X |Θ`WF u′ u′t,Γ, X |Θpi 〈et,γ〉 andΓ, X |Θ u1 ∼ u2 γ.In most cases it is a straightforward use of the induction hypothesis.The only special case is (wf-var): Γ, X |Θ`WF X ′ X ′ where X ′ ∈ (Γ, X ).If X = X ′ then [u/X ]Γ | [u/X ]Θ`WF u ut from assumption as required.Lemma B.8 (Type substitution II). If Γ, X |Θ`WF θ 〈σt,γ〉 and [u/X ]Γ | [u/X ]Θ`WF u utthen [u/X ]Γ | [u/X ]Θ`WF [u/X ]θ 〈[ut/X ]τt, [ut/X ]γ〉.Proof. Straightforward by induction on derivations Γ, X | Θ `WF θ 〈σt,γ〉 using IH andlemma B.7.In case (wf-cscheme) we can assume that X 6∈ X i using the bound variable renaming conven-tion.Lemma B.9 (Type substitution III). If Γ, X |Θ`WF σ σt and [u/X ]Γ | [u/X ]Θ`WF u utthen [u/X ]Γ | [u/X ]Θ`WF [u/X ]σ [ut/X ]σt.159Proof. If σ ∈ STYPE then the proof is immediate from lemma B.7.Otherwise σ=∀X i.pi j ⇒ τ for some X i,pi j,τ where we can assume X 6∈ X i.From lemma B.3 we getΓ, X , X i |Θ,pi j `WF pi j 〈τtj,ω j〉jand Γ, X , X i |Θ,pi j `WF τ τt and σt =∀X i.∀ω j.fn(τtj)→ τt for some τtj,ω j and τt.By lemmas B.8 and B.7 we have[u/X ]Γ, X i | [u/X ]Θ, [u/X ]pi j `WF [u/X ]pi j 〈[u/X ]τtj, [u/X ]ω j〉jand [u/X ]Γ, X i | [u/X ]Θ, [u/X ]pi j `WF [u/X ]τ [u/X ]τt.We can then use (wf-tscheme) to prove [u/X ]Γ | [u/X ]Θ`WF [u/X ]σ [u/X ]σt as required.Lemma B.10 (Weakening I).1. If Γ |Θ`WF u ut then Γ′ |Θ′ `WF u ut for any Γ′ ⊇Γ and Θ′ ⊇Θ.2. If Γ |Θpi 〈et,γ〉 then Γ′ |Θ′pi 〈et,γ〉 for any Γ′ ⊇Γ and Θ′ ⊇Θ.3. If Γ |Θ u1 ∼ u2 γ then Γ′ |Θ′ u1 ∼ u2 γ for any Γ′ ⊇Γ and Θ′ ⊇Θ.Proof. Straightforward by simultaneous induction on derivationsΓ |Θ`WF u′ u′t,Γ |Θpi 〈et,γ〉 andΓ |Θ u1 ∼ u2 γ.Lemma B.11 (Weakening II). If Γ |Θ`WF θ 〈σt,ϑ〉 then Γ′ |Θ′ `WF θ 〈σt,ϑ〉 for any Γ′ ⊇Γand Θ′ ⊇Θ.Proof. Straightforward by induction on derivations Γ |Θ`WF θ 〈σt,ϑ〉 using IH and lemmaB.10.Lemma B.12 (Weakening III). If Γ |Θ`WF σ σt then Γ′ |Θ′ `WF σ σt for any Γ′ ⊇ Γ andΘ′ ⊇Θ.Proof. If σ ∈ STYPE then the result is immediate from lemma B.10.Otherwise, the only rule that could apply as the last rule in the derivation Γ |Θ`WF σ σtis (wf-tscheme).Using lemmas B.10 and B.11 on the rule’s side conditions we getΓ′ |Θ′ `WF σ σt as required.Lemma B.13 (Weakening IV). If Γ |Θ ` e : τ et then Γ′ |Θ′ ` e : τ et for any Γ′ ⊇ Γ andΘ′ ⊇Θ.Proof. Straightforward induction on derivations Γ |Θ ` e : τ et using IH and lemma B.10when required.160Lemma B.14 (Entailed constraints are well-formed). Suppose 〈Γ,Θ〉 〈_,_〉.1. If Γ |Θpi 〈et,γ〉 then Γ |Θ`WF pi 〈τt,ω〉 for some τt,ω.2. If Γ |Θ u1 ∼ u2 γ and Γ |Θ `WF u1 ut1 then then there is some type ut2 such thatΓ |Θ`WF u2 ut2.3. If Γ | Θ u1 ∼ u2 γ and Γ | Θ `WF u2 ut2, then there is some type ut1 such thatΓ |Θ`WF u1 ut1 and.Proof. Proof by simultaneous induction on derivationsΓ |Θ u1 ∼ u2 γ and Γ |Θpi 〈et,γ〉:• Case (c-ext): Γ |Θ [ui/X i]pi 〈x[uti]Jγ jK(etj), c[uti]〉 and((x, c) :∀X i.pi j ⇒pi) ∈Θ,Γ |Θ`WF ui uti,Γ |Θ [ui/X i]pi j (etj,γ j).From well-formedness of Θ we know Γ |Θ`WF ∀X i.pi j ⇒pi 〈σt,ϑ〉 for some σt and ϑ.From lemma B.3 we get Γ, X i |Θ`WF pi j 〈τtj,ω j〉jand Γ, X i |Θ,pi j `WF pi 〈τt,ut1 ∼ ut2〉and σt =∀X i.∀ω j.fn(τtj)→ τtand ϑ=∀X i.ut1 ∼∀X i.ut2 for some τtj,ω j, c j,ut1,ut2,τt.By the assumption that X i 6∈Γ,Θ and lemma B.8,Γ |Θ, [ui/X i]pi j `WF [ui/X i]pi 〈[uti/X i]τt, [uti/X i]ut1 ∼ [uti/X i]ut2〉.From the ind. hyp. we get Γ |Θ`WF [ui/X i]pi j 〈τtj,ω j〉 for some τtj and ω j.We can then use that with lemma B.5 to showΓ |Θ`WF [ui/X i]pi 〈[uti/X i]τt, [uti/X i]ut1 ∼ [uti/X i]ut2〉 as required.• Case (c-treq1):Γ |Θ u2 : D 〈u2 i, A 7→ u4〉 〈etI SD 〈γ2,γi〉 , AD 〈sym (γ2),sym (γi)〉◦γ1 ◦γ3〉 whereΓ` u2 : D 〈u2 i〉,Γ |Θ u1 : D 〈u1 i, A 7→ u3〉 〈et,γ1〉,Γ |Θ u1 ∼ u2 γ2,Γ |Θ u1 i ∼ u2 i γiiandΓ |Θ u3 ∼ u4 γ3.By IH, Γ |Θ`WF u1 : D 〈u1 i, A 7→ u3〉 〈τt,ω〉 for some τt,ω.By lemma B.3, Γ |Θ`WF u1 ut1, and Γ |Θ`WF u1 i ut1 i,and Γ |Θ,u : D 〈u1 i〉 `WF u3 ut3, and Γ` ADfor some types ut1, ut1 i, ut3.161By lemma B.5, Γ |Θ`WF u3 ut3.We can then use the IH getΓ |Θ`WF u2 ut2,Γ |Θ`WF u2 i ut2 i, andΓ |Θ`WF u4 ut4 for some types ut2, ut2 and ut4.By lemma B.10, Γ |Θ,u2 : D 〈u2 i〉 `WF u4 ut4.Then, by rule (wf-treqcons),Γ |Θ`WF u2 : D 〈u2 i, A 7→ u4〉 〈SD 〈ut2,ut2 i〉 , AD 〈ut2,ut2 i〉 ∼ ut4〉 as required.• Case (c-treq2): Γ |Θ u2 : D 〈u2 i, A 7→?〉 〈etI SD 〈γ2,γi〉 , AD 〈ut,uti〉〉 whereΓ` u2 : D 〈u2 i〉,Γ |Θ u1 : D 〈u1 i, A 7→?〉 〈et,γ1〉,Γ |Θ u1 ∼ u2 γ2,Γ |Θ u1 i ∼ u2 i γii,Γ |Θ`WF u2 ut2,Γ |Θ`WF u2 i ut2 i.By IH, Γ |Θ`WF u1 : D 〈u1 i, A 7→ u3〉 〈τt,ω〉 for some τt,ω.By lemma B.3, Γ` AD .Then, by rule (wf-trcons),Γ |Θ`WF u2 : D 〈u2 i, A 7→?〉 〈SD 〈ut2,ut2 i〉 , AD 〈ut2,ut2 i〉 ∼ AD 〈ut2,ut2 i〉〉 as required.• Case (c-astar): Γ |Θ u : D 〈ui, A 7→?〉 〈et, AD 〈ut,uti〉〉 whereΓ |Θ u : D 〈ui, A 7→ uA〉 〈et,γ〉,Γ |Θ`WF u ut andΓ |Θ`WF ui uti.By IH, there are some τt,ω such that Γ |Θ`WF u : D 〈ui, A 7→?〉 〈τt,ω〉.By lemma B.3, Γ` u : D 〈ui〉,Γ` AD and τt = SD 〈ut,uti〉.We can then use (wf-trcons) to proveΓ |Θ`WF u : D 〈ui, A 7→?〉 〈τt, AD 〈ut,uti〉 ∼ AD 〈ut,uti〉〉.• Case (eq-sep): Γ |Θ AD 〈u,ui〉 ∼ uA γ andΓ |Θ u : D 〈ui, A ∼ uA〉 〈et,γ〉By IH Γ |Θ`WF u : D 〈ui, A ∼ uA〉 〈τt,ω〉 for some τt,ω.Lemma B.3 gives us Γ |Θ`WF u ut,Γ |Θ`WF ui uti,162Γ |Θ,u : D 〈ui〉 `WF uA utA,and Γ` AD for some types ut,uti and utA.Using (wf-atype) we get Γ |Θ`WF AD 〈u,uti〉 AD 〈ut,uti〉.Using lemma B.4 we getΓ |Θ`WF uA utA as required.• Case (eq-refl): Γ |Θ u∼ u utTrivial.• Case (eq-trans): Γ |Θ u1 ∼ u2 γ1 ◦γ2 andΓ |Θ u1 ∼ u3 γ1 andΓ |Θ u3 ∼ u2 γ2.Suppose Γ |Θ`WF u1 ut1.By IH Γ |Θ`WF u3 ut3 and then Γ |Θ`WF u2 ut2.If, on the other hand, Γ |Θ`WF u2 ut2,then by IH Γ |Θ`WF u3 ut3 for some ut3and Γ |Θ`WF u1 ut1 for some ut1 as required.• Case (eq-sym): Γ |Θ u1 ∼ u2 sym γ andΓ |Θ u2 ∼ u1 γ.If Γ |Θ`WF u1 ut1 then we can use the IH to get Γ |Θ`WF u2 ut2 as required.The symmetric case is analogous.• Case (eq-struct): Γ |Θ S 〈ui〉 ∼ S 〈u′i〉 S 〈γi〉 whereS 〈X i〉 {. . . } ∈Γ, and [ui/X i][u′i/X i] defined, and Γ |Θ ui ∼ u′i γi.Suppose Γ |Θ`WF S 〈ui〉 ut.From lemma B.3 we get Γ |Θ`WF ui uti and ut = S 〈uti〉 and S 〈_〉 {. . . } ∈Γ).From IH we get Γ |Θ`WF u′i uti for some uti.Then by (wf-struct) Γ |Θ`WF S 〈u′i〉 S 〈u′ti 〉 as required.If we assume instead Γ |Θ`WF S 〈u′i〉 then the proof is analogous.• Case (eq-ref): Straightforward use of IH, lemma B.3 and rule (wf-ref) as in the case for(eq-struct).• Case (eq-obj): Γ |Θ ∃T : D 〈u1 i, AD j 〈T,u1s j〉 ∼ u1 j〉 ∼ ∃T : D 〈u2 i, AD j 〈T,u2s j〉 ∼ u2 j〉 (∃T,&T,SD 〈T,γi〉 , AD j 〈T,γs j〉 ∼ γ j) whereSelfU : D 〈X i〉,163[u1 i/X i][u2 i/X i] defined,SelfU : D j 〈Xs j〉j,[u1s j/Xs j][u2s j/Xs j] definedj,Γ |Θ u1 i ∼ u2 i γi,Γ,T |Θ,T : D 〈u1 j, A 7→ _〉 u1s j ∼ u2s j γs j andΓ |Θ u1 j ∼ u2 j γ jSuppose Γ |Θ`WF ∃T : D 〈u1 i, AD j 〈T,u1s j〉 ∼ u1 j〉 ut1.From lemma B.3 we know that there are some ut1 i,ut1s j,ut1 j such thatΓ`D obj-safeΓ |Θ`WF u1 i u1 tiΓ,T |Θ,T : D 〈u1 i, A 7→ _〉 `WF u1s j u1 ts js jahdΓ |Θ`WF u1 j u1 tj.Then, by IH, there are some ut2 i,ut2s j,ut2 j such thatΓ |Θ`WF u2 i ut2 i,Γ,T |Θ,T : D 〈u1 j, A 7→ _〉 `WF u2s j ut2s j andΓ |Θ`WF u2 j ut2 j.By lemma B.10 we getΓ,T |Θ,T : D 〈u1 j, A 7→ _〉 ,T : D 〈u2 j, A 7→ _〉 `WF u2s j ut2s j andΓ,T |Θ,T : D 〈u2 j, A 7→ _〉 u1 j ∼ u2 j.Using (eq-sym) we get Γ,T |Θ,T : D 〈u2 j, A 7→ _〉 u2 j ∼ u1 j.Then using (c-ext) and (c-treq) we get Γ,T |Θ,T : D 〈u2 j, A 7→ _〉 T : D 〈u1 j, A 7→ _〉.We can then use lemma B.4 to proveΓ,T |Θ,T : D 〈u2 j, A 7→ _〉 `WF u2s j ut2s jFinally, using rules (wf-atype) and (wf-desc) we getΓ |Θ`WF ∃T : D 〈u2 i, AD j 〈T,u2s j〉 ∼ u2 j〉 ut2 for some ut2 as required.The proof of point 2. is similar.• Case (eq-fun): Straightforward use of IH, lemma B.3 and rule (wf-fun) as in the casefor (eq-struct).• Case (eq-atype): Γ |Θ AD 〈u1,u1 i〉 ∼ AD 〈u2,u2 i〉 AD 〈γ,γi〉 whereΓ` SelfU : D 〈X i〉,[u1/SelfU][u2/SelfU][u1 i/X i][u2 i/X i] defined,164Γ |Θ u1 ∼ u2 γ, andΓ |Θ u1 i ∼ u2 i γi.Suppose Γ |Θ`WF AD 〈u1,u1 i〉 ut.From lemma B.3 we get Γ |Θ u1 : D 〈u1 i, A 7→ _〉,Γ |Θ`WF u1 u1 t andΓ |Θ`WF ui u1 tifor some ut,u1 ti.From the IH we get Γ |Θ`WF u2 ut2 and Γ |Θ`WF u2 i ut2 i.Using (c-treq2) we get Γ |Θ u2 : D 〈u2 i, A 7→?〉.Then we can use (wf-atype) to concludeΓ |Θ`WF AD 〈u2,u2 i〉 AD 〈ut2,ut2 i〉 as required.If we suppose Γ |Θ`WF AD 〈u2,u2 i〉 u′t instead, we can use an analogous argument.Lemma B.15 (Type environment contraction).1. If Γ, x : τ |Θ`WF u ut then Γ |Θ`WF u ut.2. If Γ, x : τ |Θpi 〈et,γ〉 then Γ |Θpi 〈et,γ〉3. If Γ, x : τ |Θ u1 ∼ u2 γ then Γ |Θ u1 ∼ u2 γ.Proof. Immediate from the well-formedness and constraint entailment judgments as typeassignments in the typing environment Γ are never used in the rules.Lemma B.16 (Translation of types preserves kinds). If Γ |Θ`WF τ ut then ut ∈ STYPEt.Proof. Straightforward induction on derivations Γ |Θ`WF τ ut.Lemma B.17 (Well-typed terms have well-formed types). Suppose 〈Γ,Θ〉 〈_,_〉.If Γ |Θ` e : τ et then there is some τt such that Γ |Θ`WF τ τt.Proof. By induction on derivations Γ |Θ` e : τ et:• Case (sub): Γ |Θ` e : τ2 etI γ whereΓ |Θ` e : τ1 et andΓ |Θ τ1 ∼ τ2 γ.By IH, Γ |Θ`WF τ1 τt1 for some τt1.From lemma B.14 we get Γ |Θ`WF τ1 ∼ τ2 ω for some ωand from lemma B.3 we get Γ |Θ`WF τ2 τt2 for some τt2 as required.165• Case (as): Straightforward use of IH.• Case (unit): Holds by (wf-unit).• Case (let-un): Γ |Θ` let x= e1 in e2 : τ2 let x : τt = et1 in et2 whereΓ |Θ` e1 : τ1 et1,Γ, x : τ1 |Θ` e2 : τ2 et2 andΓ |Θ`WF τ1 τt.By IH, Γ, x : τ1 |Θ`WF τ2 τt2 for some τt2and by lemma B.15 we have Γ |Θ`WF τ2 τt2 as required.• Case (seq): Straightforward use of IH.• Case (var): Γ |Θ` x : [ui/X i]τ x[uti]Jγ jK(etj) where(x :∀X i.pi j ⇒ τ) ∈Γ andΓ |Θ`WF ui uti andΓ |Θ [ui/X i]pi j 〈etj,γ j〉j.From well-formedness of Γ,Θ we get Γ |Θ`∀X i.pi j ⇒ τ σt for some σt.From lemma B.3 we get Γ, X i |Θ,pi j 〈x j, c j〉 `WF τ τt for some τt.From lemma B.7 we get Γ |Θ, [ui/X i]pi j 〈x j, c j〉 `WF [ui/X i]τ [ui/X i]τt.Then we can use lemma B.4 to get Γ |Θ`WF [ui/X i]τ [ui/X i]τt as required.• Case (app): Γ |Θ` e(e i) : τ et(eti) whereΓ |Θ` e : fn(τi)→ τ et andΓ |Θ` e i : τi eti.By IH there is some τ′t where Γ |Θ`WF fn(τi)→ τ τ′t.By lemma B.3, there is some type τt such that Γ |Θ`WF τ τt as required.• Case (ref): Γ |Θ`&lv :&τ &lvt whereΓ |Θ` lv : τ lvt.By IH Γ |Θ`WF τ τt for some τt.We can then use (wf-ref) to get Γ |Θ`WF &τ &τt as required.• Case (deref): Γ |Θ`∗e : τ ∗et whereΓ |Θ` e :&τ et.From IH there is some τ′t where Γ |Θ`WF &τ τ′t.From lemma B.3 we get τ′t =&ut and Γ |Θ`WF τ ut.From lemma B.16 we know that ut ∈ STYPEt as required.166• Case (asgn): Immediate from (wf-unit).• Case (new-struct): Immediate from (wf-struct).• Case (proj): Γ |Θ` e.x : [u j/X j]τ et.x whereΓ |Θ` e : S 〈u j〉 et andΓ(S)= struct S 〈X j〉 {xm : τm, x : τ, xn : τn}.From Γ’s well-formedness and lemmas B.1 and B.2 we know that Γ, X j | Θ `WF τ τtfor some τt.From IH we get Γ |Θ`WF S 〈u j〉 τt for some type τt.From lemma B.3 we get Γ |Θ`WF u j utj for some types utj.We can then use lemma B.7 to get Γ |Θ`WF [u j/X j]τ [utj/X j]τt as required.• Case (obj-cast): Immediate from the rule’s side condition.Lemma B.18 (Translation of constraints preserves types). Suppose 〈Γ,Θ〉 〈Ωt,Γt〉.1. If Γ |Θpi 〈et,γ〉 and Γ |Θ`WF pi 〈τt,ω〉then Ωt |Γt | ; `T et : τt and Ωt `T γ :ω2. If Γ |Θ u1 ∼ u2 γ, and Γ |Θ`WF u1 ut1 and Γ |Θ`WF u2 ut2then Ωt `T γ : ut1 ∼ ut2Proof. By simultaneous induction on derivations Γ |Θpi 〈et,γ〉 and Γ |Θ u1 ∼ u2 γ :• Case (c-ext): Γ |Θ [ui/X i]pi 〈x[uti]Jγ jK(etj), c[uti]〉 where(∀X i.pi j ⇒pi 〈x, c〉) ∈Θ,Γ |Θ`WF ui uti andΓ |Θ [ui/X i]pi j (etj,γ j)From well-formedness of Θ we know Γ |Θ`WF ∀X i.pi j ⇒pi 〈σt,ϑ〉 for some σt and ϑ.From lemma B.3 we get Γ, X i |Θ`WF pi j 〈τtj,ω j〉jand Γ, X i |Θ,pi j `WF pi 〈τt,ut1 ∼ ut2〉and σt =∀X i.∀ω j.fn(τtj)→ τtand ϑ=∀X i.ut1 ∼∀X i.ut2 for some τtj,ω j,ut1,ut2,τt.We can use lemma B.1 to conclude that (x :σt) ∈Γt and (c :ϑ) ∈Ωt.From the assumption X i 6∈Γ,Θ and lemma B.8,Γ |Θ`WF [ui/X i]pi j 〈[uti/X i]τtj, [uti/X i]ω j〉 andΓ |Θ, [ui/X i]pi j `WF [ui/X i]pi 〈[uti/X i]τt, [uti/X i]ut1 ∼ [uti/X i]ut2〉.167Then, using lemma B.5 we getΓ |Θ`WF [ui/X i]pi 〈[uti/X i]τt, [uti/X i]ut1 ∼ [uti/X i]ut2〉.From IH we get Ωt |Γt | ; `T etj : [uti/X i]τtjjand Ωt `T γ j : [uti/X i]ω j.We can then use the typing rules of the target language as follows:Ωt |Γt | ; `T x :∀X i.∀ω j.fn(τtj)→ τt by (t-var).Ωt |Γt | ; `T x[uti] :∀[uti/X i]ω j.fn([uti/X i]τtj)→ [uti/X i]τt by (t-tapp).Ωt |Γt | ; `T x[uti]Jγ jK : fn([uti/X i]τtj)→ [uti/X i]τt by (t-capp).Ωt |Γt | ; `T x[uti]Jγ jK(etj) : [uti/X i]τt by (t-fapp) as required.Ωt `T c :∀X i.ut1 ∼∀X i.ut2 by (co-var).Ωt `T c[uti] : [uti/X i]ut1 ∼ [uti/X i]ut2 by (co-tapp) as required.• Case (c-treq1):Γ |Θ u2 : D 〈u2 i, A 7→ u4〉 〈etI SD 〈γ2,γi〉 , AD 〈sym (γ2),sym (γi)〉◦γ1 ◦γ3〉whereΓ |Θ u1 : D 〈u1 i, A 7→ u3〉 〈et,γ1〉,Γ` u2 : D 〈u2 i〉,Γ |Θ u1 ∼ u2 γ,Γ |Θ u1 i ∼ u2 i γiiandΓ |Θ u3 ∼ u4 γ3.Suppose Γ |Θ u2 : D 〈u2 i, A 7→ u4〉 〈τt2,ω2〉.By lemma B.3, there are some ut2,ut2 i,ut4 such thatΓ |Θ`WF u2 ut2,Γ |Θ`WF u2 i ut2 i,Γ |Θ,u2 : D 〈u2 i, A 7→?〉 `WF u4 ut4,τt2 = SD 〈ut2,ut2 i〉 andω2 = AD 〈ut2,ut2 i〉 ∼ ut4.By lemma B.14 Γ |Θ`WF u1 : D 〈u1 i, A 7→ u3〉 〈τt1,ω1〉 for some τt1, ω1.By lemma B.3, there are some ut1,ut1 i,ut3 such thatΓ |Θ`WF u1 ut1,Γ |Θ`WF u1 i ut1 i,Γ |Θ,u1 : D 〈u1 i, A 7→?〉 `WF u3 ut3,τt1 = SD 〈ut1,ut1 i〉 andω1 = AD 〈ut1,ut1 i〉 ∼ ut3.Using lemma B.4 we get Γ |Θ`WF u3 ut3 and Γ |Θ`WF u4 ut4.Then, by IH we get:Ωt `T γ1 : AD 〈ut1,ut1 i〉 ∼ ut3,168Ωt `T γ2 : ut1 ∼ ut2,Ωt `T γi : ut1 i ∼ ut2 i, andΩt `T γ3 : ut3 ∼ ut4.Using rule (co-struct) we get Ωt `T SD 〈γ,γi〉 : SD 〈ut1,ut1 i〉 ∼ SD 〈ut2,ut2 i〉and using (t-coerce) we get Ωt |Γt | ; `T etI SD 〈γ,γi〉 : SD 〈ut2,ut2 i〉.Using (co-sym) and (co-atype) we getΩt `T AD 〈sym (γ2),sym (γi)〉 : AD 〈ut2,ut2 i〉 ∼ AD 〈ut1,ut1 i〉.Then using (co-sym) twice again we getΩt `T AD 〈sym (γ2),sym (γi)〉◦γ1 ◦γ3 : AD 〈ut2,ut2 i〉 ∼ ut4 as required.• Case (c-treq2):Γ |Θ u2 : D 〈u2 i, A 7→?〉 〈etI SD 〈γ2,γi〉 , AD 〈ut,u2 i〉〉whereΓ |Θ u1 : D 〈u1 i, A 7→?〉 〈et,γ1〉,Γ` u2 : D 〈u2 i〉,Γ |Θ u1 ∼ u2 γ,Γ |Θ u1 i ∼ u2 i γii,Γ |Θ u2 ut2 andΓ |Θ u2 i ut2 i.Suppose Γ |Θ u2 : D 〈u2 i, A 7→?〉 〈τt2,ω2〉.By lemma B.3, there are some ut2,ut2 i such thatΓ |Θ`WF u2 ut2,Γ |Θ`WF u2 i ut2 i,τt2 = SD 〈ut2,ut2 i〉 andω2 = AD 〈ut2,ut2 i〉 ∼ AD 〈ut2,ut2 i〉.By lemma B.14 Γ |Θ`WF u1 : D 〈u1 i, A 7→?〉 〈τt1,ω1〉 for some τt1, ω1.By lemma B.3, there are some ut1,ut1 i such thatΓ |Θ`WF u1 ut1,Γ |Θ`WF u1 i ut1 i and τt1 = SD 〈ut1,ut1 i〉.Then, by IH we get:Ωt `T γ2 : ut1 ∼ ut2 andΩt `T γi : ut1 i ∼ ut2 i.Using rule (co-struct) we get Ωt `T SD 〈γ,γi〉 : SD 〈ut1,ut1 i〉 ∼ SD 〈ut2,ut2 i〉and using (t-coerce) we get Ωt |Γt | ; `T etI SD 〈γ,γi〉 : SD 〈ut2,ut2 i〉.Then, using lemma A.13 we getΩt `T AD 〈ut2,ut2 i〉 : AD 〈ut2,ut2 i〉 ∼ AD 〈ut2,ut2 i〉 as required.169• Case (c-astar): Γ |Θ u : D 〈ui, A 7→?〉 〈et, AD 〈ut,uti〉〉 whereΓ |Θ u : D 〈ui, A 7→ uA〉 〈et,γ〉,Γ |Θ`WF u ut and Γ |Θ`WF ui uti.Suppose Γ |Θ`WF u : D 〈ui, A 7→?〉 〈τt,ω〉.By lemma B.3, Γ` u : D 〈ui〉,τt = SD 〈ut,uti〉 andω= AD 〈ut,uti〉 ∼ AD 〈ut,uti〉.By lemma B.14, Γ |Θ`WF u : D 〈ui, A 7→ uA〉 〈τt,ω〉 for some τt1,ω1.By lemma B.3, τt1 = τt.Then, using IH, we get Ωt |Γt | ; `T et : τt.Using lemma A.13 we get Ωt `T AD 〈ut,uti〉 : AD 〈ut,uti〉 ∼ AD 〈ut,uti〉 as required.• Case (eq-sep): Γ |Θ AD 〈u,ui〉 ∼ uA γ whereΓ |Θ u : D 〈ui, A 7→ uA〉 〈et,γ〉.Suppose Γ |Θ`WF AD 〈u,ui〉 ut1 and Γ |Θ`WF uA utA.By lemma B.3, there are some ut, uti such thatΓ |Θ` u ut,Γ |Θ` ui uti andut1 = AD 〈ut,uti〉.By lemma B.14, there are some τt,ω such thatΓ |Θ`WF u : D 〈ui, A 7→ uA〉 〈τt,ω〉.By lemma B.3, ω= AD 〈ut,uti〉 ∼ utA.Then, by IH, Ω`T γ :ω as required.• Case (eq-refl): Γ |Θ u∼ u ut whereΓ |Θ`WF u ut.By lemma A.7, Ωt `T ut : ut ∼ ut as required.• Case (eq-trans): Γ |Θ u1 ∼ u2 γ1 ◦γ2 whereΓ |Θ u1 ∼ u3 γ1 andΓ |Θ u3 ∼ u2 γ2.Suppose Γ |Θ`WF u1 ut1 and Γ |Θ`WF u2 ut2.From lemma B.14 we get Γ |Θ`WF u3 ut3 for some ut3.From IH we get Ωt `T γ1 : ut1 ∼ ut3 and Ωt `T γ2 : ut3 ∼ ut2.We can then use rule (co-trans) to get Ωt `T γ1 ◦γ2 : ut1 ∼ ut2 as required.170• Case (eq-sym): Γ |Θ u1 ∼ u2 sym (γ) whereΓ |Θ u2 ∼ u1 γ.Suppose Γ |Θ`WF u1 ut1 and Γ |Θ`WF u2 ut2 for some ut1,ut2.By IH Ωt `T γ : ut2 ∼ ut1.We can then use (co-sym) to prove Ωt `T sym γ : ut1 ∼ ut2 as required.• Case (eq-struct): Γ |Θ S 〈u1 i〉 ∼ S 〈u2 i〉 S 〈γi〉 whereΓ |Θ u1 i ∼ u2 i γii.Suppose Γ |Θ`WF S 〈u1 i〉 ut1 and Γ |Θ`WF S 〈u2 i〉 ut2.From lemma B.3 we getΓ |Θ` u1 i ut1 i,Γ |Θ` u2 i ut2 i,ut1 = S 〈ut1 i〉, andut2 = S 〈ut2 i〉for some ut1 i,ut2 i.By IH, Ωt `T γi : ut1 i ∼ ut2 i.We can then use (co-struct) to get Ωt `T S 〈γi〉 : S 〈ut1 i〉 ∼ S 〈ut2 i〉 as required.• Case (eq-ref): Γ |Θ&u1 ∼&u2 &γ where Γ |Θ u1 ∼ u2 γ.Suppose Γ |Θ`WF &u1 u′t1 and Γ |Θ`WF &u2 u′t2 .From lemma B.3 we getΓ |Θ`WF u1 ut1,Γ |Θ`WF u2 ut2,u′t1 =&ut1 and u′t2 =&ut2 for some ut1 and ut2.Using the IH we get Ωt `T γ : ut1 ∼ ut2.Then, using (co-ref) we get Ωt `T &γ :&ut1 ∼&ut2 as required.• Case (eq-obj): Γ |Θ ∃T : D 〈u1 i, AD j 〈T,u1s j〉 ∼ u1 j〉 ∼ ∃T : D 〈u2 i, AD j 〈T,u2s j〉 ∼ u2 j〉 (∃T,&T,SD 〈T,γi〉 , AD j 〈T,γs j〉 ∼ γ j) whereΓ |Θ u1 i ∼ u2 i γi,Γ,T |Θ,T : D 〈u1 i, A 7→ _〉 u1s j ∼ u2s j γs j andΓ |Θ u1 j ∼ u2 j γ j.Suppose Γ |Θ`WF ∃T : D 〈u1 i, AD j 〈T,u1s j〉 ∼ u1 j〉 ut1 andΓ |Θ`WF ∃T : D 〈u2 i, AD j 〈T,u2s j〉 ∼ u2 j〉 ut2.171Then from lemma B.3 there are some ut1 i,ut1s j,ut1 j,ut2 i,ut2s j,ut2 j such thatΓ |Θ`WF u1 i ut1 i, Γ,T |Θ,T : D 〈u1 i, A 7→ _〉 `WF u1s j ut1 i, Γ |Θ`WF u1 j ut1 j,Γ |Θ`WF u2 i ut2 i, Γ,T |Θ,T : D 〈u2 i, A 7→ _〉 `WF u2s j ut2 i, Γ |Θ`WF u2 j ut2 j,ut1 = (∃T,&T,SD 〈T,ut1 i〉 , AD j 〈T,ut1s j〉 ∼ ut1 j) andut2 = (∃T,&T,SD 〈T,ut2 i〉 , AD j 〈T,ut2s j〉 ∼ ut2 j).Then by IH Ωt `T γi : ut1 i ∼ ut2 i,Ωt `T γs j : ut1s j ∼ ut2s j andΩt `T γ j : ut1 j ∼ ut2 j.By (co-tvar) Ωt `T T : T ∼T.By (co-ref) Ωt `T &T :&T ∼&T.By (co-struct) Ωt `T SD 〈T,γi〉 : SD 〈T,ut1 i〉 ∼ SD 〈T,ut2 i〉.By (co-atype) Ωt `T AD j 〈T,γs j〉 : AD j 〈T,ut1s j〉 ∼ AD j 〈T,ut2s j〉.Then we can apply (co-obj) to getΩt `T (∃T,&T,SD 〈T,γi〉 , AD j 〈T,γs j〉 ∼ γ j) :(∃T,&T,SD 〈T,ut1 i〉 , AD j 〈T,ut1s j〉 ∼ ut1 j)∼ (∃T,&T,SD 〈T,ut2 i〉 , AD j 〈T,ut2s j〉 ∼ ut2 j)as required.• Case (eq-fun): Γ |Θ fn(τ1 i)→ τ1 ∼ fn(τ2 i)→ τ2 fn(γi)→ γ whereΓ |Θ τ1 i ∼ τ2 i γiiandΓ |Θ τ1 ∼ τ2 γ.Suppose Γ |Θ`WF fn(τ1 i)→ τ1 ut1 and Γ |Θ`WF fn(τ2 i)→ τ2 ut2.From lemma B.3 we getΓ |Θ`WF τ1 i τt1 i,Γ |Θ`WF τ2 i τt2 i,Γ |Θ`WF τ1 τt1,Γ |Θ`WF τ2 τt2,ut1 = fn(τt1 i)→ τt1, andut2 = fn(τt2 i)→ τt2for some τt1 i,τt2,τt1,τt2.Then from IH we getΩt `T γi : τt1 i ∼ τt2 i andΩt `T γ : τt1 ∼ τt2.We can then use rule (co-fun) to getΩt `T fn(γi)→ γ : fn(τt1 i)→ τt1 ∼ fn(τt2 i)→ τt2 as required.172• Case (eq-atype): Γ |Θ AD 〈u1,u1 i〉 ∼ AD 〈u2,u2 i〉 AD 〈γ,γi〉 whereΓ |Θ u1 ∼ u2 γ andΓ |Θ u1 i ∼ u2 i γi.Suppose Γ |Θ`WF AD 〈u1,u1 i〉 u′t1 and Γ |Θ`WF AD 〈u2,u2 i〉 u′t2 .From lemma B.3 we getΓ |Θ` u1 ut1,Γ |Θ` u2 ut2,Γ |Θ` u1 i ut1 i,Γ |Θ` u2 i ut2 i,u′t1 = AD 〈ut1,ut1 i〉 and u′t2 = AD 〈ut2,ut2 i〉for some ut1,ut2,ut1 i,ut2 i.We can then use IH to getΩt `T γ : ut1 ∼ ut2 andΩt `T γi : ut1 i ∼ ut2 iand we can use rule (co-atype) to getΩt `T AD 〈γ,γi〉 : AD 〈ut1,ut1 i〉 ∼ AD 〈ut2,ut2 i〉 as required.Lemma B.19. If X 6∈Γ and Γ |Θ`WF u ut then X 6∈ FV (u,ut).Proof. Straightforward induction on derivations Γ |Θ`WF u.Theorem B.1 (Translation of terms preserves well-typedness). If:• Γ |Θ` e : τ et and• Γ |Θ`WF τ τt and• 〈Γ,Θ〉 〈Ωt,Γt〉,then Ωt |Γt | ; `T et : τt.Proof. By induction on derivations Γ |Θ` e : τ et:• Case (sub): Γ |Θ` e : τ2 etI γ whereΓ |Θ` e : τ1 et andΓ |Θ τ1 ∼ τ2 γ.Suppose Γ |Θ`WF τ2 τt2.From lemma B.17 there is some τt1 such that Γ |Θ`WF τ1 τt1.173From IH we have Ωt |Γt | ; `T et : τt1.From lemma B.14 and lemma B.16 we getΓ |Θ`WF τ1 τt1 and Γ |Θ`WF τ2 τt2for some s-types τt1,τt2.Then, we can use lemma B.18 to get Ωt `T γ : τt1 ∼ τt2.We can then apply rule (t-coerce) to concludeΩt |Γt | ; `T etI γ : τt2 as required.• Case (as): Γ |Θ` e as τ : τ et whereΓ |Θ` e : τ et.Suppose Γ |Θ` τ τt.From IH we get Ωt |Γt | ; `T et ` τt as required.• Case (unit): Γ |Θ` () : () ()By (wf-unit) Γ |Θ` () () andby (t-unit) Ωt |Γt | ; `T () : () as required.• Case (let-un): Γ |Θ` let x= e1 in e2 : τ2 let x : τt1 = et1 in et2 whereΓ |Θ` e1 : τ1 et1,Γ, x : τ1 |Θ` e2 : τ2 et2 andΓ |Θ`WF τ1 τt1.Suppose Γ |Θ` τ2 τt2.By lemma B.10 Γ, x : τ1 |Θ` τ2 τt2.〈(Γ, x : τ1),Θ〉 〈Ωt, (Γt, x : τt1)〉 by definition of environment translation.Then by IH Ωt |Γt | ; `T et1 : τt1 andΩt |Γt, x : τt1 | ; ` et2 : τt2.We can then apply (t-let) to get Ωt |Γt | ; `T let x : τt1 = et1 in et2 : τt2 as required.• Case (seq): Γ |Θ` e1; e2 : τ2 et1; et2 whereΓ |Θ` e1 : τ1 et1 andΓ |Θ` e2 : τ2 et2.Suppose Γ |Θ` τ2 τt2.By lemma B.17 Γ |Θ` τ1 τt1 for some τt1.Then, by IH Ωt |Γt | ; `T et1 : τt1 and Ωt |Γt | ; `T et2 : τt2.We can then apply rule (t-seq) to get Ωt |Γt | ; `T et1; et2 : τt2 as required.174• Case (var): Γ |Θ` x : [ui/X i]τ x[uti]Jγ jK(etj) where(x :∀X i.pi j ⇒ τ) ∈Γ,Γ |Θ`WF ui uti andΓ |Θ [ui/X i]pi j 〈etj,γ j〉j.Suppose Γ |Θ`WF [ui/X i]τ τt1.By lemma B.1 there is some type scheme σt where (x :σt) ∈Γt andΓ |Θ`WF ∀X i.pi j ⇒ τ σt.From lemma B.3 we know that σt =∀X i.∀ω j.fn(τtj)→ τtwhere Γ, X i |Θ`WF pi j 〈τtj,ω j〉jand Γ, X i |Θ,pi j 〈x j, c j〉 `WF τ τtfor some τtj,ω j, c j,τt.From lemma B.7 we get Γ |Θ`WF [ui/X i]pi j 〈[uti/X i]τtj, [uti/X i]ω j〉jand Γ |Θ, [ui/X i]pi j 〈x j, c j〉 `WF [ui/X i]τ [uti/X i]τt.So τt1 = [uti/X i]τt.From lemma B.18 we getΩt |Γt | ; `T etj : [uti/X i]τtjjandΩt `T γtj : [uti/X i]ω jj.We can then apply rule(t-var) to get Ωt |Γt | ; `T x :∀X i.∀ω j.fn(τtj)→ τt,rule (t-tapp) to get Ωt |Γt | ; `T x[uti] :∀[uti/X i]ω j.fn([uti/X i]τtj)→ [uti/X i]τt,rule (t-capp) to get Ωt |Γt | ; `T x[uti]Jγ jK : fn([uti/X i]τtj)→ [uti/X i]τt andrule (t-fapp) to get Ωt |Γt | ; `T x[uti]Jγ jK(etj) : [uti/X i]τt as required.• Case (app): Γ |Θ` e(e i) : τ et(eti) whereΓ |Θ` e : fn(τi)→ τ et andΓ |Θ` e i : τi eti.Suppose Γ |Θ`WF τ τt.From lemma B.17 there are some τti where Γ |Θ`WF τi τti.We can use rule (wf-fun) to get Γ |Θ` fn(τi)→ τ fn(τti)→ τt.Then from IH we get Ωt |Γt | ; `T et : fn(τti)→ τt and Ωt |Γt | ; `T eti : τti.We can then apply rule (t-fapp) to get Ωt |Γt | ; `T et(eti) : τt as required.• Case (ref): Γ |Θ`&lv :&τ &lvt whereΓ |Θ` lv : τ lvt.175Suppose Γ |Θ`WF &τ τt1.By lemma B.17 there is some τt such that Γ |Θ`WF τ τt.Then by (wf-ref) Γ |Θ`WF &τ &τtso τt1 =&τt.By IH Ωt |Γt | ; `T lvt : τt.We can then apply rule (t-ref) to get Ωt |Γt | ; `T &lvt :&τt as required.• Case (deref): Γ |Θ`∗e : τ ∗et whereΓ |Θ` e :&τ et.Suppose Γ |Θ`WF τ τt.We can use rule (wf-ref) to get Γ |Θ`WF &τ &τt.Then by IH Ωt |Γt | ; `T et :&τt.We can then use rule (t-deref) to get Ωt |Γt | ; `T ∗et τt as required.• Case (asgn): Γ |Θ` lv := e : () lvt := et whereΓ |Θ` lv : τ lvt andΓ |Θ` e : τ et.Suppose Γ |Θ`WF () τt1.From lemma B.3 we know that τt1 = ().From lemma B.17 we know that there is some τt such that Γ |Θ`WF τ τt.We can then use IH to get Ωt |Γt | ; `T lvt : τt and Ωt |Γt | ; `T et : τt.We can then use rule (t-upd) to get Ωt |Γt | ; `T lvt := et : () as required.• Case (new-struct): Γ |Θ` S{xi : e i} : S 〈uk〉 S 〈utk〉 {xi : eti} whereS 〈Xk〉 {xi : τi} ∈Γ,Γ |Θ` e i : [uk/Xk]τi eti andΓ |Θ`WF uk utk.Suppose Γ |Θ`WF S 〈uk〉 τt.From lemmas B.1 and B.2 we know that S 〈Xk〉 {xi : τti} ∈Ωtfor some τti where Γ, Xk |Θ`WF τi τti.From lemma B.3 we get τt = S 〈utk〉.By lemma B.7, Γ |Θ`WF [uk/Xk]τi [utk/Xk]τti.We can use the IH to get Ωt |Γt | ; `T eti : [utk/Xk]τti.176We can then apply rule (t-newstruct) to get Ωt | Γt | ; `T S 〈utk〉 {xi : eti} : S 〈utk〉 as re-quired.• Case (proj): Γ |Θ` e.x : [u j/X j]τ et.x whereΓ |Θ` e : S 〈u j〉 et andΓ(S)= struct S 〈X j〉 {xm : τm, x : τ, xn : τn}.Suppose Γ |Θ`WF [u j/X j]τ τt1.From lemmas B.1 and B.2 we know that S 〈Xk〉 {xm : τtm, x : τt, xn : τtn} ∈Ωtfor some τtm,τt,τtn where Γ, Xk |Θ`WF τ τt.From lemmas B.17 and B.3 we get Γ |Θ`WF S 〈u j〉 S 〈utj〉where Γ |Θ`WF u j utj for some utj.By IH Ωt |Γt | ; `T et : S 〈utj〉.By lemma B.7, Γ |Θ`WF [u j/X j]τ [utj/X j]τt so τt1 = [utj/X j]τt.Then we can use rule (t-proj) to get Ωt |Γt | ; `T et.x : [utj/X j]τt as required.• Case (obj-cast): Γ |Θ` e :&(∃T : D 〈ui,u1 j ∼ u2 j〉) pack (τt1, et, etD ,γ j) as τt2 whereΓ |Θ` e :&τ et ,Γ |Θ`WF τ τt1 ,Γ |Θ τ : D 〈ui〉 etD ,Γ |Θ [τ/T]u1 j ∼ u2 j γ j ,Γ |Θ (∃T : D 〈ui,u1 j ∼ u2 j〉) : D 〈ui〉 andΓ |Θ`WF &(∃T : D 〈ui,u1 j ∼ u2 j〉) τt2.From lemma B.3 we know that there are some AD j,us j,u j,uti,uts j,utj such thatu1 j = AD j 〈T,us j〉,Γ |Θ`WF ui uti,Γ,T |Θ,T : D 〈ui, A 7→ _〉 `WF us j uts j,Γ |Θ`WF u2 j u2 tj andτt2 = (∃T,&T,SD 〈T,uti〉 , AD j 〈T,uts j〉 ∼ utj).By rule (wf-ref) Γ |Θ`WF &τ &τt1and by IH Ωt |Γt | ; `T et :&τt1.By lemmas B.14 and B.3, Γ |Θ`WF τ : D 〈ui〉 SD 〈τt1,uti〉and by lemma B.18, Ωt |Γt | ; `T etD : SD 〈τt1,uti〉.By (wf-atype), Γ,T |Θ,T : D 〈ui, A 7→ _〉 `WF AD j 〈T,us j〉 AD j 〈T,uts j〉.Using lemma B.7, we getΓ |Θ`WF [τ/T]AD j 〈T,us j〉 AD j 〈τt1, [τt1/T]uts j〉.177As T 6∈Γ, lemma B.19 gives us T 6∈ FV (ui,u2 j,uti,u2 tj).Thus [τt1/T]SD 〈T,uti〉 = SD 〈τti,uti〉 and [τ/T]ut2 j = ut2 j.Then by lemma B.18 Ωt `T γ j : AD j 〈τt1,uts j〉 ∼ u2 tj.We can then apply rule (t-pack) to proveΩt |Γt | ; `T pack (τt1, et, etD ,γ j) as τt2 : τt2 as required.Lemma B.20 (Environment extension). If• 〈Γ,Θ〉 〈Ωt,Γt〉,• Γ,Γ′ |Θ,Θ′ `Γ′ 〈Ωt1,Γt1〉 and• Γ,Γ′ |Θ,Θ′ `Θ′ 〈Ωt2,Γt2〉where the domains of Γ,Γ′ and Θ,Θ′ respectively do not overlap, then〈(Γ,Γ′), (Θ,Θ′)〉 〈(Ωt,Ωt1,Ωt2), (Γt,Γt1,Γt2)〉.Proof. From rule (tr-envs) we know that there are some Ωt3,Ωt4,Γt3,Γt4 such that{Ωt3,Ωt4}=Ωt,{Γt3,Γt4}=Γt,Γ |Θ`Γ 〈Ωt3,Γt3〉 andΓ |Θ`Θ 〈Ωt4,Γt4〉.A simple simultaneous induction on derivations Γ |Θ`Γ 〈Ωt3,Γt3〉 and Γ |Θ`Θ 〈Ωt4,Γt4〉using lemmas B.10, B.11 and B.12 lets us show thatΓ,Γ′ |Θ,Θ′ `Γ 〈Ωt3,Γt3〉 and Γ,Γ′ |Θ,Θ′ `Θ 〈Ωt4,Γt4〉.Then, applying lemma B.1 and the environment translation rules we getΓ,Γ′ |Θ,Θ′ `Γ,Γ′ 〈(Ωt3,Ωt1), (Γt3,Γt1)〉 and Γ,Γ′ |Θ,Θ′ `Θ,Θ′ 〈(Ωt4,Ωt2), (Γt4,Γt2)〉.Applying (tr-envs) we then get 〈(Γ,Γ′), (Θ,Θ′)〉 〈(Ωt,Ωt1,Ωt2), (Γt,Γt1,Γt2)〉 as required.Lemma B.21 (Soundness of supertrait hierarchy relation). Suppose 〈Γ,Θ〉 〈Ωt,Γt〉.If Γ`D 〈ui〉 ⇑ {β j} and Γ |Θ SelfU : D 〈ui〉 then Γ |Θ SelfU :β j.Proof. From the relation ⇑’s only rule we getΓ`D 〈ui〉 ⇑{β j s, D 〈ui, A 7→?〉}where(D 〈X i〉 where _,SelfU : Ds 〈uns, As 7→ us〉 _, A : _,_,_) ∈Γ andΓ`Ds 〈[ui/X i]uns〉 ⇑ {β j s}s.Γ |Θ u : D 〈ui, A 7→?〉 by assumption.Using lemma B.1 we get (∀SelfU, X i.(SelfU : D 〈X i〉)⇒ SelfU : D 〈uns, As 7→ us〉 _s) ∈Θ.178Then using (c-ext) and (c-astar) we get Γ |Θ SelfU : Ds 〈[ui/X i]uns, As 7→?〉.Then by IH we get Γ |Θ SelfU :β j s as required.Lemma B.22. Suppose 〈Γ, (Θ1,Θ2)〉 〈Ωt,Γt〉.If Γ |Θ1 |Θ2 `pi1Vpi2 γ and Γ |Θ1,Θ2 `WF pi1 τt1 thenΓ |Θ1 `WF pi2 τt2 and Ωt `T γ : τt1 ∼ τt2.Proof. By rule induction on Γ |Θ1 |Θ2 `pi1Vpi2 γ.• Let pi1 = u1 : D 〈u1 i, A 7→ u3〉 and pi2 = u2 : D 〈u2 i, A 7→ u4〉.Then Γ |Θ1 |Θ2 ` u1 : D 〈u1 i, A 7→ u3〉V u2 : D 〈u2 i, A 7→ u4〉 SD 〈γ1,γi〉 andΓ |Θ1,Θ2 u1 ∼ u2 γ1,Γ |Θ1,Θ2 u1 i ∼ u2 i γii,Γ |Θ1,Θ2 u3 ∼ u4,Γ |Θ1 `WF u2 : D 〈u2 i, A 7→ u2〉.By lemma B.3, Γ |Θ1,Θ2 `WF u1 ut1 and Γ |Θ2,Θ2 `WF u1 i ut1 i.By lemma B.3 and lemma B.10,Γ |Θ1,Θ2 `WF u2 ut2, and Γ |Θ1,Θ2 `WF u2 i ut2 i, andτt1 = SD 〈ut1,ut1 i〉 and τt2 = SD 〈ut2,ut2 i〉By theorem B.18, Ωt `T γ1 : ut1 ∼ ut2 and Ωt `T γ1 : ut1 i ∼ ut1 i.Then using (co-struct), Ωt `T SD 〈γ1,γi〉 : SD 〈ut1,ut1 i〉 ∼ SD 〈ut2,ut2 i〉 as required.• Let pi1 = u1 : D 〈u1 i, A 7→?〉 and pi2 = u2 : D 〈u2 i, A 7→?〉.Then Γ |Θ1 |Θ2 ` u1 : D 〈u1 i, A 7→?〉V u2 : D 〈u2 i, A 7→?〉 SD 〈γ1,γi〉 andΓ |Θ1,Θ2 u1 ∼ u2 γ1,Γ |Θ1,Θ2 u1 i ∼ u2 i γii,Γ |Θ1 `WF u2 : D 〈u2 i, A 7→ u2〉.By lemma B.3, Γ |Θ1,Θ2 `WF u1 ut1 and Γ |Θ2,Θ2 `WF u1 i ut1 i.By lemma B.3 and lemma B.10,Γ |Θ1,Θ2 `WF u2 ut2, and Γ |Θ1,Θ2 `WF u2 i ut2 i, andτt1 = SD 〈ut1,ut1 i〉 and τt2 = SD 〈ut2,ut2 i〉By theorem B.18, Ωt `T γ1 : ut1 ∼ ut2 and Ωt `T γ1 : ut1 i ∼ ut1 i.Then using (co-struct), Ωt `T SD 〈γ1,γi〉 : SD 〈ut1,ut1 i〉 ∼ SD 〈ut2,ut2 i〉 as required.Lemma B.23 (Soundness of dictionary path relation). If• 〈Γ,Θ〉 〈Ωt,Γt〉,179• Γ` u : D1 〈ui〉 7→D2 〈u j〉 et1,• Γ |Θ`WF u j utj,• Γ |Θ`WF u : D1 〈ui〉 SD1 〈ut,uti〉,• Γ |Θ u : D1 〈ui〉• (D 〈X j〉where _,SelfU : _,_, f ,_),• ( f :∀SelfU, X j.(SelfU : D2 〈X j〉)⇒σ) ∈Γ, and• Γ |Θ`WF σ σtthen Ωt |Γt, xdict : SD1 〈ut,uti〉 | ;`T xdict.et1 : [ut/SelfU][utj/X j]σt.Proof. By induction on derivations Γ |Θ`WF u : D1 〈ui〉 7→D2 〈u j〉 et1.• Case (path1): Γ` u : D1 〈ui〉 7→D2 〈u j〉 x.et where(D1 〈X i〉 where _,SelfU :βs xs,_,, _),(D3 〈uk, A 7→ _〉 x) ∈{[u/SelfU][ui/X i]βs xs}andΓ` u : D3 〈uk〉 7→D2 〈u j〉 et.From lemma B.1 we get(∀X p.(SelfU : D1 〈X i〉)⇒ SelfU : D3 〈u′k〉 〈x, c〉) ∈Θ,Γ, X p |Θ,SelfU : D1 〈X i〉 `WF SelfU : D3 〈u′k〉 〈τt3,ω3〉 andSD1 〈X p〉 {. . . , x : τt3, . . . } ∈Ωtwhere uk = [u/SelfU][ui/X i]u′k.By lemma B.3, τt3 = SD3 〈SelfU,u′tk 〉 for some u′tk .Then, using rule (c-ext) we get Γ |Θ u : D3 〈uk〉.By lemma B.3, Γ |Θ`WF u ut and Γ |Θ`WF ui uti.Then, by lemma B.5 and lemma B.3,Γ |Θ`WF u : D3 〈uk〉 〈SD3 〈ut,utk〉 ,_〉 where utk = [ut/SelfU][uti/X i]u′tk .Then, by IH, we get Ωt |Γt, x3 : SD3 〈ut,utk〉 | ;`T x3.et : [ut/SelfU][utj/X j]σt.Using rules (t-var) and (t-proj) we getΩt |Γt, xdict : SD1 〈ut,uti〉 | ;`T xdict.x : SD3 〈ut,utk〉.Then, using lemma A.5 and A.6, we getΩt |Γt, xdict : SD1 〈ut,uti〉 | ;`T xdict.x.et : [ut/SelfU][utj/X j]σt as required.• Case (path2): Γ` u : D1 〈ui〉 7→D1 〈ui〉 fwhere (D1 〈X i〉 where _,_,_, f ,_).180By lemma B.1, SD1 〈SelfU, X i〉 { f :σt, . . . } ∈Ωt.Note that uti = utj and X i = X j.Then, using (t-var) and (t-proj) we getΩt |Γt, xdict : SD1 〈ut,uti〉 | ;`T xdict. f : [ut/SelfU][utj/X j]σt as required.Lemma B.24 (Soundness of auxiliary object-safe trait relation). If1. Γ |Θ | θd 〈_, c′d〉 `os uobj : D 〈ui, A 7→ X 〉 〈etD ,pis x′s,pia x′a〉,2. 〈Γ,Θ〉 〈Ωt,Γt〉,3. 〈Γ, (Θ,θd 〈_, c′d〉)〉 〈(Ωt, c′d :ϑ′d), (Γt,_)〉4. Γ |Θ`WF uobj utobj5. Γ |Θ,θd 〈_, c′d〉 `WF uobj : D 〈ui〉 τtD .then1. Γ |Θ`WF pis τ′ts ,2. Γ |Θ`WF pia τ′ta ,3. Ωt, c′d :ϑ′d |Γt, x′s : τ′ts , x′a : τ′ta | ; `T etD : τtD .Proof. By lemma B.3,Γ |Θ,θd 〈_, c′d〉 `WF uobj utobj,Γ |Θ,θd 〈_, c′d〉 `WF ui uti,and τtD = SD 〈utobj,uti〉 for some utobj,uti.Let X p = SelfU, X i and up = uobj,ui and utp = utobj,uti.From the relation `os’s side conditions,(D 〈X i〉 where _,SelfU :βs xs, A :βa xa, f ,obj-safe) ∈Γ.By lemma B.1, SD 〈X p〉 { f :σt, xs : τts, xa : τta} ∈Ωt whereσt = fn(&SelfU,τtm)→ τtR ,Γ, X p |Θ,SelfU : D 〈X i〉 `WF SelfU :βs 〈τts,ωs〉sandΓ, X p |Θ,SelfU : D 〈X i〉 `WF AD 〈X p〉 :βa 〈τta,ωa〉a.181By lemma B.8,Γ |Θ,θd 〈_, c′d〉 `WF uobj : [up/X p]βs 〈[utp/X p]τts,_〉sandΓ |Θ,θd 〈_, c′d〉 `WF AD 〈up〉 : [up/X p]βa 〈[up/X p]τta,_〉aBy lemma B.22, there are some τ′ts ,τ′ta such thatΓ |Θ`WF pis τ′ts ,Γ |Θ`WF pia τ′ta ,Ωt, c′d :ϑ′d `T γs : [utp/X p]τts ∼ τ′tssandΩt, c′d :ϑ′d `T γa : [utp/X p]τta ∼ τ′taa.Let Θ′′ =Θ,T : Dobj 〈Xh〉 x.Using lemma B.3 on uobj and (wf-trcons) we getΓ′ |Θ`WF T : Dobj 〈Xh〉 SDobj 〈T, Xh〉.Using lemma B.20 we get 〈Γ′,Θ′′〉 〈Ωt, (Γt,T, x : SDobj 〈T, Xh〉)〉.Using lemma B.3 we know that there are some types u′ti such thatΓ′ |Θ′′ `WF u′i u′ti .By (c-ext) we get Γ′ |Θ′′ T : Dobj 〈Xh〉.We can then use lemma B.23 to getΩt |Γt,T, x : SDobj 〈T, Xh〉 | ;`T xdict.etP : fn(&T, [T/SelfU][u′ti /X i]τtm)→ [T/SelfU][u′ti /X i]τtR .From the side conditions we haveΓ′ =Γ,T andΘ′ =Θ,T : Dobj 〈Xh〉 ,T : Dd 〈und, A 7→ Xd〉 〈_, cd〉Using a combination of lemma B.3 and well-formedness rules we have 〈Γ′,Θ′〉 〈Ωt0,Γt3〉for some Ωt0,Γt0 where Ωt0 =Ωt, c′d :ϑ′d, cd : AD d 〈T,utnd〉 ∼ Xd.Using lemma B.3 we getΓ,SelfU, X i |Θ,SelfU : D 〈X i〉 `WF τR τtR andΓ,SelfU, X i |Θ,SelfU : D 〈X i〉 `WF τm τtmm.Using lemma B.10 we getΓ′,SelfU, X i |Θ′,SelfU : D 〈X i〉 `WF τR τtR ,Γ′,SelfU, X i |Θ′,SelfU : D 〈X i〉 `WF τm τtmm.Γ′ |Θ′,uobj : D 〈ui〉 `WF up utpp, andΓ′ |Θ′,T : D 〈u′i〉 `WF u′i utii.Using lemma B.7 we getΓ′ |Θ′,uobj : D 〈ui〉 `WF [up/X p]τR [utp/X p]τtR ,182Γ′ |Θ′,uobj : D 〈ui〉 `WF [up/X p]τm [uti/X i]τtmm,Γ′ |Θ′,T : D 〈u′i〉 `WF [T/SelfU][u′i/X i]τR [T/SelfU][u′ti /X i]τtR ,Γ′ |Θ′,T : D 〈u′i〉 `WF [T/SelfU][u′i/X i]τm [T/SelfU][u′ti /X i]τtmm.From lemma’s assumptions and lemma B.11 we get Γ′ |Θ′ `WF uobj : D 〈ui〉 τtD .We can then use lemma B.4 to getΓ′ |Θ′ `WF [up/X p]τR [utp/X p]τtR ,Γ′ |Θ′ `WF [up/X p]τm [uti/X i]τtmm,Since (T : D 〈u′i〉) ∈ {T : Dd 〈und〉}, we can use lemma B.4 to getΓ′ |Θ′ `WF [T/SelfU][u′i/X i]τR [T/SelfU][u′ti /X i]τtR andΓ′ |Θ′ `WF [T/SelfU][u′i/X i]τm [T/SelfU][u′ti /X i]τtmm.Then by lemma B.18 we haveΩt0 ` γ : [T/SelfU][uti/X i]τtR ∼ [utp/X p]τtR andΩt0 ` γm : [utp/X p]τtm ∼ [T/SelfU][uti/X i]τtmmUsing lemma B.3 we get τtD = SD 〈utobj,uti〉.Let u′tp =T,u′ti .Let et1 = let (T, xval, xdict, cd)= unpack xobj in et2,et2 = xdict.etP . f (xval, xmI γm)I γ ,Γt0 =Γt, x′s : τ′ts , x′a : τ′ta ,Γt1 =Γt0, xobj :&utobj, xm : [utp/X p]τtm andΓt2 =Γt1,T, xval :&T, xdict : SD 〈T, Xh〉.By lemma A.5, Ωt0 |Γt2 ` xdict.etP : SD 〈T,u′ti 〉.We can then obtain the derivationD1 D2 DmΩt0 |Γt2 ` xdict.etP . f (xval, xmI γm) : [u′tp/X p]τtR(t-fapp)Ωt0 ` γ : [u′tp/X p]τtR ∼ [utp/X p]τtRΩt0 |Γt2 ` xdict.etP . f (xval, xmI γm)I γ : [utp/X p]τtR(t-coerce)Ωt, c′d :ϑ′d |Γt1 ` let (T, xval, xdict, cd)= unpack xobj in et2 : [utp/X p]τtR(t-unpack)Ωt, c′d :ϑ′d |Γt0 ` fn (xobj :&utobj, xm : [utp/X p]τtm) { et1 } : fn(&utobj, [utp/X p]τtm)→ [utp/X p]τtR(t-fabs)183whereD1 =Ωt0 |Γt2 ` xdict.etP : SD 〈T,u′ti 〉Ωt0 |Γt2 ` xdict.etP . f : fn(&T, [u′tp/X p]τtm)→ [u′tp/X p]τtR(t-proj)D2 = Ωt2 |Γt2 ` xval :&T(t-var)Dm =Ωt0 |Γt2 ` xm : [utp/X p]τtm(t-var)Ωt0 ` γm : [utp/X p]τtm ∼ [u;tp /X p]τtmΩt0 |Γt2 ` xmI γm : [u;tp /X p]τtm(t-coerce)In all above derivations we assume an empty store typing environment Σ.We have proved earlier thatΩt, c′d :ϑ′d `T γs : [utp/X p]τts ∼ τ′tssandΩt, c′d :ϑ′d `T γa : [utp/X p]τta ∼ τ′taa.Then, using (co-sym) and (t-coerce), we getΩt, c′d :ϑ′d |Γt0 | ; `T x′sI sym γs : [utp/X p]τtssandΩt, c′d :ϑ′d |Γt0 | ; `T x′aI sym γs : [utp/X p]τtaa.We can then use (t-newstruct) to prove Ωt, c′d :ϑ′d |Γt0 | ; `T etD : SD 〈utp〉 as required.Lemma B.25 (Well-typed items generate well-formed environments).Suppose Γ′ ⊆ Γ and Θ′ ⊆ Θ. If Γ | Θ ` item : Γ′ | Θ′ pgmt then there are some Ωt1,Ωt2,Γt1,Γt2such that Γ |Θ`Γ′ 〈Ωt1,Γt1〉 and Γ |Θ`Θ′ 〈Ωt2,Γt2〉.Proof. By induction on derivations Γ |Θ` item :Γ′ |Θ′ pgmt:• Case (struct): Γ′ = {S 〈X j〉〈xi : τi〉} and Θ′ =;where Γ, X j |Θ`WF τi τti.By (Θ;), Γ |Θ`; 〈;,;〉.By (Γsct), Γ |Θ` S 〈X j〉 {xi : τi} 〈{S 〈x j〉},;〉 as required.• Case (fun): Γ′ = { f :σ} and Θ′ =;where Γ |Θ`WF σ σt.By (Θ;), Γ |Θ`; 〈;,;〉.By (Γvar), Γ |Θ` { f :σ} 〈;, { f :σt}〉.• Case (trait): Γ′ = {(D 〈X i〉where pih, Self :βs xs, A :βa xa, obj-unsafe), f :σ′} andΘ′ = {∀X p.(Self : D 〈X i〉)⇒Self :βs 〈xD,s, cD,s〉s,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈xD,a, cD,a〉a}.184The rule’s side conditions are sufficient to prove with (Γvar) and (Γtrt) thatΓ |Θ`Γ′ 〈{S 〈X p〉 { f :σt, xs : τts, xa : τta}, AD 〈X p〉}, { f :σ′t}〉.With the rule’s side conditions we can also use Θθ twice to proveΓ |Θ`Θ′ 〈{cD,s :ϑs, cD,a :ϑa}, {xD,s :∀X p.fn(SD 〈X p〉)→ τts, xD,a :∀X p.fn(SD 〈X p〉)→ τta}〉as required.• Case (impl): Γ′ =; and Θ′ = {∀Xk.pi j ⇒ u : D 〈ui, A 7→ uA〉 〈xu:D〈ui〉, cu:D〈ui〉〉}.Using the rule’s side conditions with well-formedness judgments and lemma B.3, wecan deduce Γ |Θ`WF ∀Xk.pi j ⇒ u : D 〈ui, A 7→ uA〉 〈σtD ,∀Xk.AD 〈utp〉 ∼ utA〉.Then using (Θθ) we getΓ |Θ`Γ′ 〈{cu:D〈ui〉 :∀Xk.AD 〈utp〉 ∼∀Xk.utA}, {xu:D〈ui〉 :σtD}〉as required.• Case (obj-trt): Γ′ = {(D 〈X i〉where pih, Self :βs xs, A :βa xa, obj-unsafe), f :σ′} andΘ′ = {∀X p.(Self : D 〈X i〉)⇒Self :βs 〈xD,s, cD,s〉s,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈xD,a, cD,a〉a,∀X i, Xd.pid mm ⇒pid 〈xd, cd〉d}.The rule’s side conditions are sufficient to prove with (Γvar) and (Γtrt) thatΓ |Θ`Γ′ 〈{S 〈X p〉 { f :σt, xs : τts, xa : τta}, AD 〈X p〉}, { f :σ′t}〉.With the rule’s side conditions we can also use Θθ to proveΓ |Θ`Θ′ 〈{cD,s :ϑs, cD,a :ϑa, cd :∀X i.Xd.utd ∼∀X i.Xd.Xd},{xD,s :∀X p.fn(SD 〈X p〉)→ τts, xD,a :∀X p.fn(SD 〈X p〉)→ τta,xd :∀X i.Xd.∀ωd m.fn(τtd m)→ τtd}〉as required.Theorem B.2 (Translation of items preserves well-typedness). Suppose Γ′ ⊆Γ and Θ′ ⊆Θ.If Γ |Θ` item :Γ′ |Θ′ itemti and 〈Γ,Θ〉 〈Ωt,Γt〉then there are some Ωt1,Ωt2,Γt1,Γt2,Ωti,Γti such that :• Γ |Θ`Γ′ 〈Ωt1,Γt1〉,• Γ |Θ`Θ′ 〈Ωt2,Ωt2〉,• Ωt |Γt `T itemti :Ωti |Γti,• Ωti =Ωt1,Ωt2 and185• Γti =Γt1,Γt2.Proof. By induction on derivations Γ |Θ` item :Γ′ |Θ′ itemti.• Case (struct):Γ |Θ` struct S 〈X j〉 {xi : τi} : [S 〈X j〉 {xi : τi}] | ; struct S 〈X j〉 {xi : τti}where Γ, X j |Θ`WF τi τtii.Suppose 〈Γ,Θ〉 〈Ωt,Γt〉.Then, using the environment translation judgment we get{Ωt1,Ωt2}= [S : S 〈X j〉 {xi : τti}] and {Γt1,Γt2}=;.By rule (t-struct) Ωt |Γt ` struct S 〈X j〉 {xi : τti} : [S 〈X j〉 {xi : τti}] | ; as required.• Case (fun): Γ |Θ` fn f 〈Xk〉 (xi : τi)→ τwhere pi j { e } : [ f :σ] | ; f :σt =ΛXk.Λc j :ω j.fn (x j : τtj){ fn (xi : τti){ et } } whereσ=∀Xk.pi j ⇒ fn(τi)→ τ ,Γ |Θ`WF σ σt ,σt =∀Xk.∀ω j.fn(τtj)→ fn(τti)→ τt ,Γ′′ =Γ, Xk, xi : τi ,Θ′′ =Θ,pi j 〈x j, c j〉 andΓ′′ |Θ′′ ` e : τ etSuppose 〈Γ,Θ〉 〈Ωt,Γt〉.From the environment translation and from Γ |Θ`WF σ σt we get{Ωt1,Ωt2}=; and {Γt1,Γt2}= [ f :σt].From lemma B.3 we getΓ, Xk |Θ`WF pi j 〈τtj,ω j〉j,Γ, Xk |Θ,pi j 〈x j, c j〉 `WF fn(τi)→ τ fn(τti)→ τt,Γ, Xk |Θ,pi j 〈x j, c j〉 `WF τi τti andΓ, Xk |Θ,pi j 〈x j, c j〉 `WF τ τt.Using lemmas B.10 and B.11 we getΓ′′ |Θ′′ `WF pi j 〈τtj,ω j〉j,Γ′′ |Θ′′ `WF τi τti andΓ′′ |Θ′′ `WF τ τt.From the environment translation judgment we get〈Γ′′ |Θ′′〉 〈(Ωt, c j :ω j), (Γt, Xk, xi : τti, x j : τtj)〉.From theorem B.1 we get Ωt, c j :ω j |Γt, Xk, xi : τti, x j : τtj ` et : τt.186We can then obtain the following derivation:(t-tabs)(t-cabs)(t-fabs)(t-fabs)Ωt, c j :ω j |Γt, Xk, x j : τtj, xi : τti | ; ` et : τtΩt, c j :ω j |Γt, Xk, x j : τtj | ; ` fn (xi : τti){ et } : fn(τti)→ τtΩt, c j :ω j |Γt, Xk | ; ` fn (x j : τtj){ fn (xi : τti){ et } } : fn(τtj)→ fn(τti)→ τtΩt |Γt, Xk | ; `Λc j :ω j.fn (x j : τtj){ fn (xi : τti){ et } } :∀ω j.fn(τtj)→ fn(τti)→ τtΩt |Γt | ; `ΛXk.Λc j :ω j.fn (x j : τtj){ fn (xi : τti){ et } } :∀Xk.∀ω j.fn(τtj)→ fn(τti)→ τtWe can then apply rule (t-decl) to getΩt |Γt ` f :σt =ΛXk.Λc j :ω j.fn (x j : τtj){ fn (xi : τti){ et } } :; | [ f :σt] as required.• Case (trait):item= trait D 〈X i〉where pi j {type A :βa; f :σ; }Γ′ = [(D 〈X i〉where pih, Self :βs xs, A :βa xa, f ,obj-unsafe), f :σ′]Θ′ = [∀X p.(Self : D 〈X i〉)⇒Self :βs 〈xD,s, cD,s〉s,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈xD,a, cD,a〉a]itemti =type AD 〈X p〉 ;axiom cD,a :ϑaa;axiom cD,s :ϑss;struct SD 〈X p〉 { f :σt, xs : τts, xa : τta}f :σ′t =ΛX p, Xk.Λcl :ωl .fn (xD : SD 〈X p〉 , xl : τtl){ (xD . f )[Xk]JclK(xl) };xD,s :∀X p.fn(SD 〈X p〉)→ τts =ΛX p.fn (xD : SD 〈X p〉){xD .xs};sxD,a :∀X p.fn(SD 〈X p〉)→ τta =ΛX p.fn (xD : SD 〈X p〉){xD .xa};aSide conditions:{pi j}≡ {(Self :βs),pih}X p =Self, X iΓ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒pih _hσ=∀Xk.pil ⇒ fn(τm)→ τRσ′ =∀X p, Xk.(Self : D 〈X i〉 ,pil)⇒ fn(τm)→ τRΓ |Θ`WF σ′ σ′tΓ, X p |Θ,Self : D 〈X i〉 `WF σ σtσt =∀Xk.∀ωl .fn(τtl)→ fn(τtm)→ τtRΓ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒Self :βs 〈∀X p.fn(SD 〈X p〉)→ τts,ϑs〉sΓ |Θ`WF ∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa 〈∀X p.fn(SD 〈X p〉)→ τta,ϑa〉aSuppose 〈Γ,Θ〉 〈Ωt,Γt〉.Using the rule’s side conditions and the environment translation rules we get187Γt1 = [ f :σ′t],Ωt1 = [AD 〈X p〉 , S 〈X p〉 { f :σt, xs : τts, xa : τta}],Γt2 = [xD,s :∀X p.fn(SD 〈X p〉)→ τtss, xD,a :∀X p.fn(SD 〈X p〉)→ τtaa] andΩt2 = [cD,s :ϑs, cD,a :ϑa].It follows that {Ωt1,Ωt2}⊆Ωt and {Γt1,Γt2}⊆Γt.Then by (t-type) Ωt |Γt ` type AD 〈X p〉 : [AD 〈X p〉] | ;.From lemma B.3 we get ϑs =∀X p.AD s 〈us,uns〉 ∼∀X p.uA s,(Ds 〈Xns〉where _, Xs : _, A : _,_,_)s∈Γ and[us/Xs][usn/Xsn] definedfor some AD s,us,usn and AD s 〈Xsn〉. Then by lemma B.1, AD s 〈Xs, Xsn〉 ∈Ωt.Then by (t-type) Ωt |Γt ` axiom cD,s :ϑs : [cD,s :ϑs] | ;s.Following similar reasoning we get Ωt |Γt ` axiom cD,a :ϑa : [cD,a :ϑa] | ;a.By (t-struct),Ωt |Γt ` struct S 〈X p〉 { f :σt, xs : τts, xa : τta} : [S 〈X p〉 { f :σt, xs : τts, xa : τta}] | ;.Using the well-formedness judgments we getΓ |Θ`∀X p, Xk.(Self : D 〈X i〉 ,pil)⇒ fn(τm)→ τR ∀X p, Xk.∀ωl .fn(SD 〈X p〉 ,τtl)→ fn(τtm)→ τtRso σ′t =∀X p, Xk.∀ωl .fn(SD 〈X p〉 ,τtl)→ fn(τtm)→ τtR .Using the target language typing rules (and combining some steps for conciseness) weget the following derivation:Ωt1 |Γt1 | ; ` xD . f :∀Xk.∀ωl .fn(τtl)→ fn(τtm)→ τtRΩt1 |Γt1 | ; ` (xD . f )[Xk]JclK : fn(τtl)→ fn(τtm)→ τtR Ωt1 |Γt1 | ; ` xl : τtl lΩt1 |Γt1 | ; ` (xD . f )[Xk]JclK(xl) : fn(τtm)→ τtRΩt1 |Γt, X p, Xk | ; ` fn (xD : SD 〈X p〉 , xl : τtl){ (xD . f )[Xk]JclK(xl) } : fn(SD 〈X p〉 ,τtl)→ fn(τtm)→ τtRΩt |Γt | ; `ΛX p, Xk.Λcl :ωl .fn (xD : SD 〈X p〉 , xl : τtl){ (xD . f )[Xk]JclK(xl) }:∀X p, Xk.∀ωl .fn(SD 〈X p〉 ,τtl)→ fn(τtm)→ τtRwhere Ωt1 =Ωt, cl :ωl and Γt1 =Γt, X p, Xk, xD : SD 〈X p〉 , xl : τtl .We can then use (t-decl) to getΩt |Γt ` f :σ′t =ΛX p, Xk.Λcl :ωl .fn (xD : SD 〈X p〉 , xl : τtl){ (xD . f )[Xk]JclK(xl) }:; | [ f :σ′t].For each xD,s we get the following derivation:188Ωt |Γt, X p, (xD : SD 〈X p〉 | ;` xD .xs : τtsΩt |Γt, X p | ; ` fn (xD : SD 〈X p〉){xD .xs} : fn(SD 〈X p〉)→ τtsΩt |Γt | ; `ΛX p.fn (xD : SD 〈X p〉){xD .xs} :∀X p.fn(SD 〈X p〉)→ τtsUsing (t-decl) we then getΩt |Γt ` xD,s :∀X p.fn(SD 〈X p〉)→ τts =ΛX p.fn (xD : SD 〈X p〉){xD .xs}:;, [xD,s :∀X p.fn(SD 〈X p〉)→ τts]sSimilarly, we getΩt |Γt ` xD,a :∀X p.fn(SD 〈X p〉)→ τta =ΛX p.fn (xD : SD 〈X p〉){xD .xa}:;, [xD,a :∀X p.fn(SD 〈X p〉)→ τta]aWe then have Γti = {Γt1,Γt2} and Ωti = {Ωt1,Ωt2} as required.• Case (impl):item= impl〈Xk〉D 〈ui〉 for uwhere pi j { type A = uA; fun }Γ′ =;Θ′ = [∀Xk.pi j ⇒ u : D 〈ui, A ∼ uA〉 〈xu:D〈ui〉, cu:D〈ui〉〉]itemti =axiom cu:D〈ui〉 :∀Xk.AD 〈utp〉 ∼∀Xk.utAxu:D〈ui〉 :σtD =ΛXk.Λc j :ω j.fn (x j : τtj) { SD 〈utp〉 { f : etF , xs : ets, xa : eta }};Side conditions:(D 〈X i〉where pih, Self :βs xss, A :βa xaa, f ,_) ∈Γup = u,uiX p =Self, X iΘ∗ =Θ\{∀X p.(Self : D 〈X i〉)⇒Self :βs _s,∀X p.(Self : D 〈X i〉)⇒ AD 〈X p〉 :βa _a}Γ, Xk |Θ∗,pi j 〈x j, c j〉 [up/X p](Self :βs) 〈ets,γs〉sΓ, Xk |Θ∗,pi j 〈x j, c j〉 [up/X p]pih _hΓ, Xk |Θ∗,pi j 〈x j, c j〉 `WF uA utAΓ, Xk |Θ∗,pi j 〈x j, c j〉 (AD 〈up〉 : [up/X p]βa) 〈eta,γa〉a( f :∀X p.(Self : D 〈X i〉)⇒σ) ∈ΓΓ, Xk |Θ∗,pi j 〈x j, c j〉 ` fun : [ f :σ′] | ; f :σ′t = etFσ′ = [up/X p]σΓ |Θ`WF ∀Xk.pi j ⇒ u : D 〈ui〉 σtDσtD =∀Xk.∀ω j.fn(τtj)→ SD 〈utp〉Using lemma B.3 we getΓ, Xk |Θ,pi j _`WF pi j 〈τtj,ω j〉j,Γ, Xk |Θ,pi j _`WF u : D 〈ui〉 SD 〈utp〉 andΓ, Xk |Θ,pi j _`WF up utp.189Using lemma B.10 we getΓ, Xk |Θ,pi j _`WF uA utA.Using (wf-atype) we getΓ, Xk |Θ,pi j _`WF AD 〈up〉 AD 〈utp〉.Using (wf-eqcons), lemma B.10 and (wf-cocons) we getΓ, Xk |Θ,pi j _`WF u : D 〈ui, A ∼ uA〉 〈SD 〈utp〉 , AD 〈utp〉 ∼ utA〉.Then we can use (wf-cscheme) to getΓ |Θ`WF ∀Xk.pi j ⇒ u : D 〈ui, A ∼ uA〉 〈σtD ,∀Xk.AD 〈utp〉 ∼∀Xk.utA〉Then using the environment translation rules we getΩt1 =;,Γt1 =;,Ωt2 = [cu:D〈ui〉 :∀Xk.AD 〈utp〉 ∼∀Xk.utA],Γt2 = [xu:D〈ui〉 :σtD].Using (t-axiom) we getΩt |Γt ` axiom cu:D〈ui〉 :∀Xk.AD 〈utp〉 ∼∀Xk.utA : [cu:D〈ui〉 :∀Xk.AD 〈utp〉 ∼∀Xk.utA] | ;.Using lemma B.20 we get 〈Γ, Xk |Θ,pi j 〈x j, c j〉〉 〈Ωt, c j :ω j |Γt, Xk, x j : τtj〉.From lemma B.1 we getΓ, X p |Θ,Self : D 〈X i〉 _`WF Self :βs 〈τts,ωs〉s,Γ, X p |Θ,Self : D 〈X i〉 _`WF AD 〈X p〉 :βa 〈τta,ωa〉a,( f :∀X p, Xn.(Self : D 〈X i〉 ,pil)⇒ τF ) ∈Γ,Γ, X p |Θ,Self : D 〈X i〉 _`WF ∀Xn.pil ⇒ τF σt andSD 〈X p〉 { f :σt, xs : τts, xa : τta} ∈Ωtfor some τts,ωs,τta,ωa, Xn,pil ,τF ,σt.Then σ=∀Xn.pil ⇒ τF and σ′ =∀Xn.pi′l → τ′Fwhere pi′l = [up/X p]pil and τ′F = [up/X p]τ′tF .From lemma B.3 we get σt =∀Xn.∀ωl .fn(τtl)→ τtF for some ωl ,τtl and τtF .(fun) is the only rule that could have been used as the last rule in the derivationΓ, Xk |Θ∗,pi j 〈x j, c j〉 ` fun : [ f :σ′] | ; f :σ′t = etF .Then from the rule’s side conditions we get:σ′ =∀Xn.pi′l ⇒ fn(τ′m)→ τ′R ,Γ, Xk |Θ∗,pi j 〈x j, c j〉 `WF σ′ σ′t ,σ′t =∀Xn.∀ω′l .fn(τ′tl )→ fn(τ′tm)→ τ′tR ,Γ′′ =Γ, Xk, Xn, xm : τ′m ,190Θ′′ =Θ∗,pi j 〈x j, c j〉,pil 〈xl , cl〉 andΓ′′ |Θ′′ ` e : τR et andetF =ΛXn.Λcl :ω′l .fn (xl : τ′tl ){ fn (xm : τ′tm){ et } }.Using lemma B.12 we get Γ, Xk |Θ,pi j 〈x j, c j〉 `WF σ′ σ′t.Let Θ′′′ =Θ,pi j 〈x j, c j〉,pi′l 〈xl , cl〉.Using lemma B.13 we get Γ′′ |Θ′′′ ` e : τ′R et.Then by (fun) Γ, Xk |Θ,pi j 〈x j, c j〉 ` fun : [ f :σ′] | ; f :σ′t = etF .Now we want to show that σ′t = [utp/X p]σt.By lemma B.12 we getΓ, Xk, X p |Θ,pi j 〈x j, c j〉,Self : D 〈X i〉 _`WF σ σt.From lemma B.10 we get Γ, Xk |Θ,pi j 〈x j, c j〉,u : D 〈ui〉 _`WF up utp.By lemma B.9 we getΓ, Xk |Θ,pi j 〈x j, c j〉,u : D 〈ui〉 _`WF [up/X p]σ [up/X p]σt.Since (∀Xk.pi j ⇒ u : D 〈ui, A ∼ uA〉 〈xu:D〈ui〉, cu:D〈ui〉〉) ∈Θ,we can apply (c-ext) and (c-sep) to getΓ, Xk |Θ,pi j 〈x j, c j〉 u : D 〈ui〉 xu:D〈ui〉[Xk]Jc jK(x j)We can then apply lemma B.6 to getΓ | Xk |Θ,pi j 〈x j, c j〉 `WF [up/X p]σ [utp/X p]σt as required.From lemmas B.3, B.10 and B.11 we getΓ′′ |Θ′′′ `WF pi′l 〈τ′tl ,ω′l〉,Γ′′ |Θ′′′ `WF τ′m τ′tm andΓ′′ |Θ′′′ `WF τ′R τ′tR .By lemma B.20 we have 〈Γ′′,Θ′′′〉 〈(Ωt, c j :ω j, cl :ω′l), (Γt, Xk, x j : τtj, Xn, xl : τ′tl , xm : τ′tm)〉.By theorem B.1, Ωt, c j :ω j, cl :ω′l |Γt, Xk, x j : τ′tj , Xn, xl : τ′tl , xm : τ′tm | ; ` et : τ′tR .Using (t-fabs) twice we getΩt, c j :ω j, cl :ω′l |Γt, Xk, x j : τtj, Xn | ; ` fn (xl : τ′tl ){fn (xm : τ′tm){et}}: fn(τ′tl )→ fn(τ′tm)→ τ′tR .Then, using (t-cabs) and (t-tabs) we getΩt, c j :ω j |Γt, Xk, x j : τtj | ; ` etF :σ′t.We already know Γ, X p |Θ,Self : D 〈X i〉 _`WF Self :βs 〈τts,ωs〉s.By lemmas B.11, B.8 and B.5 we getΓ, Xk |Θ,pi j _`WF [up/X p](Self :βs) 〈[utp/X p]τts, [utp/X p]ωs〉s.191Following the same process we getΓ, Xk |Θ,pi j _`WF [up/X p](AD 〈up〉 :βa) 〈[utp/X p]τta, [utp/X p]ωa〉a.Then using lemma B.18 we getΩt, c j :ω j |Γt, Xk, x j : τtj | ; ` et : [utp/X p]τtssandΩt, c j :ω j |Γt, Xk, x j : τtj | ; ` et : [utp/X p]τtaaWe can then get the following derivation:Ωt, c j :ω j |Γt, Xk, x j : τtj | ; ` SD 〈utp〉 { f : etF , xs : ets, xa : eta } : SD 〈utp〉Ωt, c j :ω j |Γt, Xk | ; ` fn (x j : τtj) { SD 〈utp〉 { f : etF , xs : ets, xa : eta }} : fn(τtj)→ SD 〈utp〉Ωt |Γt | ; `ΛXk.Λc j :ω j.fn (x j : τtj) { SD 〈utp〉 { f : etF , xs : ets, xa : eta }} :σtDUsing (t-fun) we getΩt |Γt ` xu:D〈ui〉 :σtD =ΛXk.Λc j :ω j.fn (x j : τtj) { SD 〈utp〉 { f : etF , xs : ets, xa : eta }}: [xu:D〈ui〉 :σtD] | ;.We then haveΩti = [cu:D〈ui〉 :∀Xk.AD 〈utp〉 ∼∀Xk.utA] andΓti = [xu:D〈ui〉 :σtD]as required.• Case (obj-trt): Note that the outputs of (trait) are a subset of the outputs of (obj-trt).As such, their proof is the same as in the proof for (trait). We only show the proof forthe additional outputs.Θ′ = {. . . ,∀X i, Xd.pid mm ⇒pid 〈xd, cd〉d}itemti =xd :∀X i, Xd.∀ωd m.fn(τtd m)→ τtd =ΛX i, Xd.Λcd m :ωd m.fn (xd m : τtd m) {etd};daxiom cd :∀X i, Xd.utd 7→ Xd;dSide conditions:Γ, X p `D 〈X i〉 ⇑{Dd 〈ud nn, Ad 7→ _〉d}Ad :: Xduobj =∃T : D 〈X i, AD d 〈T, [T/SelfU]ud nn〉 ∼ Xdd〉pid = uobj : Dd 〈[uobj/SelfU]ud nn, Ad 7→ Xd〉dΓ, X i, Xd |Θ | ∀X i, Xd.pid 〈xd, cd〉 `os pid 〈etd,pid m xd m〉dΓ |Θ`WF ∀X i, Xd.pid mm ⇒pid 〈∀X i, Xd.∀ωd m.fn(τtd m)→ τtd, ∀X i.Xd.utd ∼∀X i.Xd.Xd〉dUsing lemma B.21 and lemma B.8 we getΓ, X i, Xd,T |Θ,T : D 〈X i〉 `WF T : Dd 〈[T/SelfU]uns, Ad 7→?〉d.192We can then use (wf-desc) to show Γ, X i, Xd |Θ`WF uobj.Using lemma B.21 again we get Γ, X i, Xd |Θ,uobj : D 〈X i〉 `WF pid.Let θd =∀X i.Xd.pid.From the definition of the relation ⇑ we know that D 〈X i, A 7→?〉 ∈pid,so Γ, Xd, X i |Θ,θd `WF uobj : D 〈X i〉.Then, we can use lemma B.5 to prove Γ, X i, Xd |Θ,θd `WF pid.From lemma B.3, if Γ |Θ`WF ∀X i, Xd.pid mm ⇒pid 〈_,ϑd〉dandΓ |Θ`WF θd 〈_,ϑ′d〉dthen ϑd =ϑ′d.Then we can use lemma B.22 to get Γ, X i, Xd |Θ`WF pid m andΩt, cd :ϑd |Γt, xd m : τtd m | ; `T τtd.Since Θ′ ⊆Θ, we conclude that cd :ϑd ∈Ωt.Then we can use rules (t-fabs), (t-cabs), (t-capp) and (t-decl) to prove that xd are well-typed. Similarly we can use (t-axiom) to prove that axioms cd are well-typed.Theorem B.3 (Translation of programs preserves well-typedness). If `P pgm pgmt : Γ |Θand then there are some Ωt,Γt such that 〈Γ,Θ〉 〈Ωt,Γt〉 and `T pgmt :Ωt |Γt.Proof. By inversion of the well-typed programs judgment we get if `P itemi : Γ | Θ pgmtthen Γ |Θ` itemi :Γi |Θi pgmti, and Γ=Γi, and Θ=Θi and pgmt = pgmti.Using lemma B.25 we get some Ωt1 i,Ωt2 i,Γt1 i,Γt2 i such thatΓ |Θ`Γi 〈Ωt1 i,Γt1 i〉 and Γ |Θ`Θi 〈Ωt2 i,Γt2 i〉.Let Γt =Γt1 i,Γt2 i and Ωt =Ωt1 i,Ωt2 i.By lemma B.20 we get 〈Γ,Θ〉 〈Ωt,Γt〉.Then using theorem B we get Γ |Θ` itemi :Ωt1 i,Ωt2 i |Γt1 i,Γt2 ii.We can then use (t-pgm) to show `T itemti :Ωt |Γt.193Appendix CTrait coherence proofsDefinition C.1. Define δΓ as follows:δΓ(()) = ()δΓ(T) = TδΓ(fn(τi)→ τ) = fn(δΓ(τi))→ δΓ(τ)δΓ(&τ) = &δΓ(τ)δΓ(S 〈τi〉) =S 〈δΓ(τi)〉 if S 〈Ti〉 {. . . } ∈ΓTδ otherwiseδΓ(τ : D 〈τi〉) = δΓ(τ) : D 〈δΓ(τi)〉Lemma C.1 (Well-formedness inversion lemma).1. If Γ`WF T then T ∈Γ.2. If Γ`WF fn(τi)→ τ then Γ`WF τi and Γ`WF τ.3. If Γ`WF &τ then Γ`WF τ.4. If Γ`WF S 〈τi〉 then S 〈Ti〉 {. . . } ∈Γ for some Ti and Γ`WF τi.5. If Γ`WF ∀Ti.pi j ⇒pi then Γ,Ti `WF pi j and Γ,Ti `WF pi.6. If Γ`WF τ : D 〈τi〉. then Γ`WF D 〈Ti〉 for some Ti and Γ`WF τ and Γ`WF τi.Proof. Straightforward induction on derivations in the NanoRust well-formedness judgmentsin figure 3.2.Lemma C.2. If Π `OR K .τ : D 〈τn〉 then either ltenv (Π,K) ` D or there is some τ′ ∈ {τ,τn}such that Π`LT K.τ′ and FV (τi) where τi are all types that precede τ′ in the sequence [τ,τn].Proof. Straightforward from the orphan relation.194Lemma C.3. If Γ,T `WF pi then δΓ(pi)=pi.Proof. Suppose pi= τ : D 〈τi〉.By lemma C.1, Γ,T `WF τ and Γ,T `WF τi.We prodeed by induction on τ to show that if Γ,T `WF τ then δΓ(τ)= τ.There is only one interesting case: (wf-struct) where τ= S 〈τ j〉 and , S 〈T j〉 {. . . } ∈Γ.Then δΓ(S 〈T j〉)= S 〈T j〉.The same reasoning applies for for Γ,T `WF τi.Then, using the definition of δΓ we get if δΓ(pi)=pi.Lemma C.4. If Π`LT K .τ then τ=&S 〈τi〉 where S 〈Ti〉 {. . . } ∈ ltenv (Π,K) for some S,τi,Ti.Proof. Straightforward from the definition of the local type relation.Lemma C.5. Suppose no overlapping identifiers in environments in Π.If Π`LT K .τ and Π`K ′ 6vK then tenv (Π,K ′) 6`WF τ.Proof. Using lemma C.4 we get τ=&S 〈τi〉 where S 〈Ti〉 {. . . } ∈ ltenv (Π,K) for some S,τi,Ti.Since Π` K ′ 6v K and because of the no-overlap assumption, we can conclude that there areno Ti such that S 〈Ti〉 {. . . } ∈ tenv ((Π,K ′)), which based on lemma C.1 lets us conclude thattenv (Π,K ′) 6`WF τ.Lemma C.6. Suppose no overlapping identifiers in environments in Π.If ltenv (Π,K)`D and Π`K ′ 6vK then tenv (Π,K ′)0D.Proof. Analogous to the proof of lemma C.5.Lemma C.7.1. If θ ∈ cenv (Π,K) then there is some crate K ′ such that Π`K vK ′ and θ ∈ lcenv (Π,K ′).2. If tenv (Π,K)`D then there is some crate K ′ such thatΠ`K vK ′ and ltenv (Π,K ′)`D.3. If tenv (Π,K)` S then there is some crate K ′ such that Π`K vK ′ and ltenv (Π,K ′)` S.Proof.1. By induction on the relation v, assuming that the lemma holds for θ ∈ cenv (Π,K ′)all K ′ such that Π ` K @ K ′. We can make this inductive argument because of therestriction on Π, which prevents circular crate dependencies, which in turn makes therelation well-founded.Let Π(K)= 〈{K i},Γ,Θ〉. Then cenv (Π,K)= cenv (Π,K i)i,Θ.Either θ ∈ cenv (Π,K ′′) for some K ′′ ∈K i or θ ∈Θ.195If the θ ∈Θ then θ ∈ lcenv (Π,K) by def. of lcenv.If θ ∈ cenv (Π,K ′′), then Π`K @K ′′.By IH, there is some K ′ such that Π`K ′′ vK ′ and θ ∈ lcenv (Π,K ′).Then, by def. of the relation v, Π`K vK ′ as required.2. Analogous to the proof of 1.3. Analogous to the proof of 1.Lemma C.8. IfΠ`LT K.τ and there are no overlapping identifiers between Γ and ltenv (Π,K),then δΓ(τ) ∈BLANKETTYPE.Proof. By induction on derivations Π`LT K .τ.• Case (l-ref): τ=&τ′ and Π`LT K .τ′.Then by IH δΓ(τ′) ∈BLANKETTYPE. Then δΓ(&τ′)=&δΓ(τ′) ∈BLANKETTYPE.• Case (l-struct): τ= S 〈τi〉 and S 〈Ti〉 {. . . } ∈ ltenv (Π,K).There are no T ′i such that S 〈T ′i〉 {...} ∈Γ because of the no-overlap assumption.So δΓ(S 〈τi〉)=Tδ ∈BLANKETTYPE.Lemma C.9. If Π`LT K .τ then Π`LT K . [τi/Ti]τ for any types τi and type variables Ti.Proof. By induction on derivations Π`LT K .τ.• Case (l-ref): τ=&τ′ and Π`LT K .τ′.Then by IHΠ`LT K.[τi/Ti]τ′ and by (l-ref) and def. of substitution,Π`LT K.[τi/Ti](&τ′).• Case (l-struct): τ= S 〈τ j〉 and S 〈T j〉 {. . . } ∈ ltenv (Π,K).[τi/Ti]S 〈τ j〉 = S 〈[τi/Ti]τ j〉 and so by (l-struct) Π`LT K .S 〈[τi/Ti]τ j〉.Lemma C.10. If Π`LT K .δΓ(τ) then Π`LT K .τ.Proof. By induction on derivations Π`LT K .τ.• Case (l-ref): If δΓ(τ)=&τ′ then τ′ = δΓ(τ′′) and τ=&τ′′ for some τ′′ by definition of δΓ .Then Π`LT K .δΓ(τ′′) by the rule’s premise and, by IH, Π`LT K .τ′′.Then by (l-ref) Π`LT K .&τ′′ as required.196• Case (l-struct): If δΓ(τ)= S 〈τi〉 then τi = δΓ(τ′i) and τ= S 〈τ′i〉with S 〈Ti〉 {. . . } ∈Γ for some τ′i and Ti.From the rule’s premise S 〈Ti〉 ∈ ltenv (Π,K).Then by (l-struct), Π`LT K .S 〈τ′i〉 as required.Lemma C.11. If FV (δΓ(τ))=; then FV (τ)=;.Proof. By structural induction on τ• Case (): Trivial.• Case fn(τi)→ τ:δΓ(fn(τi)→ τ)= fn(δΓ(τi))→ δΓ(τ).By IH, FV (τi,τ)=; and so FV (fn(τi)→ τ) as required.• Case &τ: δΓ(&τ)=&δΓ(τ).By IH, FV (τ)=; so FV (&τ)=;.• Case T: δΓ(T)=T and FV (T)=T so this case is vacuous.• Case S 〈τi〉: If δΓ(S 〈τi〉)=Tδ then this case is vacuous as FV (Tδ)=Tδ.Otherwise, δΓ(S 〈τi〉)= S 〈δΓ(τi)〉. By IH, FV (τi)=; so FV (S 〈τi〉)=;.Lemma C.12. If Π`OR K .δΓ(pi) then Π`OR K .pi.Proof. By induction on derivations Π`OR K .δΓ(pi).• Case (orph1): Trivial.• Case (orph2): pi= τ : D 〈τi〉 and Π`LT K .δΓ(τ). Using lemma C.10 we get Π`LT K .τso Π`OR K .pi using (orph2).• Case (orph2): pi= τ0 : D 〈τi,τ,τ j〉 and Π`LT K .δΓ(τ) and FV (δΓ(τ0),δΓ(τi))=;.Then by lemma C.10 Π`LT K .τ and by lemma C.11 FV (τ0,τi)=;so by (orph2), Π`OR K .pi.Lemma C.13. If τ 6∈ BLANKETTYPE and tenv (Π,K1) `WF τ and Π ` K2 @ K1 then for anytype substitution φ, Π 6`LT K2.φ(τ).197Proof. If Π`K2@K1 then ltenv (Π,K2) and tenv (Π,K1) have no overlapping identifiers.Suppose for contradiction that Π`LT K2.φ(τ).Then, by lemma C.4, φ(τ)=&S 〈τi〉 for some S and τi and ltenv (Π,K)` S.Since Π`K1 6vK2, lemma C.5 gives us tenv (Π,K1) 6`WF φ(τ).Since τ is not a blanket type it can only have form &S 〈τ′i〉. But then, since tenv (Π,K1) 0 S,this is impossible.Lemma C.14. Let K be a consistent crate under Π where Π=Π′′∪ {K : 〈{Ka},ΓK ,ΘK 〉} and letΠ′ = [K ′/K]Π′′∪ {K ′ : 〈{Ka},ΓK ,ΘK ∪ {θ1}〉} where K ′ is consistent in Π′.Then, for any crate K1, if Π`OR K1.pi then Π′ `OR [K ′/K]K1.pi.Moreover, if Π`LT K1.τ then Π′ `LT [K ′/K]K1.τ.Proof. Straightforward from the definition of the orphan rule and local type relations as therelations don’t use constraint environments.Theorem 8.2 (Trait coherence). Suppose:• (K : 〈{Kr},ΓK ,ΘK 〉) ∈Π,• each crate K ′ ∈Kr is consistent in Π,• 〈tenv (Π,K),cenv (Π,K)〉 well-formed,• every impl in ΘK obeys the orphan rule w.r.t. crate K, and• for every pair of impl constraints schemes θ1 ∈ΘK and θ2 ∈ cenv (Π,K),θ1 and θ2 don’t overlap under Π and cenv (Π,K).Then K is consistent in Π.Proof. Let Γ= tenv (Π,K) and Θ= cenv (Π,K).We must show that for every pair of distinct impl constraint schemes θ1 and θ2 ∈Θ there isno overlap.We know that Θ= cenv (Π,K)=⋃ {cenv (Π,Kr)r,ΘK } by definition.From the theorem’s assumptions,we know that if θ1 ∈ΘK and θ2 ∈Θ then θ1,θ2 don’t overlap in Π,Θ.We must show the same for each θ1 ∈Θ′ where Θ′ =⋃ {cenv (Π,Kr)r}.Let K1 ∈Kr and let Γ1 = tenv (Π,K1) and Θ1 = cenv (Π,K1).Then let Γ2 =Γ\Γ1 and Θ2 =Θ\Θ1.Let θ1 ∈ lcenv (Π,K3) and θ2 ∈ lcenv (Π,K4) for some crates K3,K4.We consider two cases:198• Case 1: Π`K3 6vK4 and Π`K4 6vK3.Suppose that there exists a substitution φ such that φ(τ1 : D 〈τ1 i〉)=φ(τ2 : D 〈τ2 i〉).By lemma C.1, tenv (Π,K3)`D and tenv (Π,K4)`D.Since we are assuming non-overlapping trait identifiers in Π, by lemma C.7 there issome crate K5 such that ltenv (Γ,K5)`D where Π`K3 vK5 and Π`K4 vK5.Since Π`K3 6vK4 and Π`K4 6vK3, we can conclude that K5 6=K3 and K5 6=K4.From the definition of consistent crates,Π`OR K3.τ1 : D 〈τ1 i〉 and Π`OR K4.τ2 : D 〈τ2 i〉.Let τ1,τ1 i = [τ11, . . . ,τ1n] and τ2,τ2 i = [τ21, . . . ,τ2n] where n is the length of the sequence.Then from the orphan rules we know that there are some τ1p and τ2qsuch that Π`LT K3.τ1p and Π`LT K4.τ2qwith FV (τ11, . . . ,τ1r,τ21, . . . ,τ2s)=;where r = p−1 and s= q−1.Then one of the following is true:– Case p= q: From lemma C.4, τ1p =&S1 〈τ〉 where S1 〈T〉 {. . . } ∈ ltenv (Π,K3).Similarly, τ2p =&S2 〈τ〉 where S2 〈T〉 {. . . } ∈ ltenv (Π,K4).Since the local environments of K3 and K4 are not allowed to overlap, S1 6= S2 andso there is no substitution φ such that φ(τ1p)=φ(τ2p).– Case p< q: From lemma C.4, τ1p =&S1 〈τ〉 where S1 〈T〉 {. . . } ∈ ltenv (Π,K3)and from lemma C.2, FV (τ2 p)=; since p< q.So, since φ(τ1p)=φ(τ2p), then τ2p =&S1 〈τ′〉.Using lemma C.1, we get S1 〈T〉 {. . . } ∈ tenv (Π,K4) for some T.However, due to non-overlapping identifiers in Πand the fact that Π`K4 6vK3, this is impossible by lemma C.5.– Case p> q: Analogous to the previous case.Since all above cases are impossible, we have derived a contradiction: no such φ asdefined above can exist.• Case 2: Π`K3 vK4.Let Θ1 = cenv (Π,K1) and Γ1 = cenv (Π,K1). Note that Θ1 ⊆ Θ and Γ1 ⊆ Γ. We knowthat θ1 and θ2 don’t overlap under environments Π, Γ1 and Θ1 from consistency of K1.To derive a contradiction, we want to show that if θ1 and θ2 overlap under Π,Γ,Θ thenthey also overlap under Π,Γ1,Θ1.Specifically we’ll show that if there is a substitution φ such thatφ(τ1 : D 〈τ1 i〉)=φ(τ2 : D 〈τ2 i〉) andΠ |ΘK4.φ(pi) for each pi ∈ {pik,pim}199then there is a substitution φ′ such that φ′(τ1 : D 〈τ1 i〉)=φ′(τ2 : D 〈τ2 i〉) andΠ |Θ1 K4.φ′(pi) for each pi ∈ {pik,pim}.Wlog, suppose φ= [τn/Tn]. Then let φ′ = [δΓ1(τn)/Tn].From consistency of K1 it follows that Γ1 `WF θ1 and Γ2 `WF θ2.From lemma C.1 we get Γ1,T j `WF τ1 : D 〈τ1 i〉 and Γ1,Tl `WF τ2 : D 〈τ2 i〉with Γ1 `D 〈Ti〉.Then, we can use lemma C.3 to get δΓ1(τ1 : D 〈τ1 i〉)= τ1 : D 〈τ1 i〉and δΓ1(τ2 : D 〈τ2 i〉)= τ2 : D 〈τ2 i〉.It then follows that φ′(τ1 : D 〈τ1 i〉)= δΓ1(φ(τ1 : D 〈τ1 i〉))and φ′(τ2 : D 〈τ2 i〉)= δΓ1(φ(τ2 : D 〈τ2 i〉)).As δΓ1 is a deterministic function, we can conclude that φ′(τ1 : D 〈τ1 i〉)=φ′(τ2 : D 〈τ2 i〉).Using the well-formedness inversion lemma we also getΓ1,T j,Tl `WF pi for all pi ∈ {pik,pim}.It then follows that φ′(pi)= δΓ1(φ(pi)) for each such pi.Let pi= τ3 : D3 〈τm〉.Then from the well-formedness inversion lemma we get Γ1 `D3 〈Tm〉.We now use induction to show that if pi= τ : D 〈τi〉, and Γ1 `D 〈Ti〉, and Π |Θ K4.pithen Π |ΘK4.δΓ1(pi).We proceed by rule induction on Π |ΘK4.pi:– Case (cons): Then pi= [τi/Ti]pi′ and ∀Ti.pi j ⇒pi′ ∈Θ and Π |ΘK4. [τi/Ti]pi j.LetΘ2 =Θ\Θ1 and Γ2 =Γ\Γ1. Then ∀Ti.pi j ⇒pi′ is either inΘ1 orΘ2. We considerboth cases separately:* Case ∀Ti.pi j ⇒pi′ ∈Θ1:Then from consistency of K1 we know that Θ1 is well-formed,and so Γ1,Ti `WF pi j and Γ1,Ti `WF pi′.Moreover, suppose wlog that pi j = τ j : D j 〈T〉. Then Γ1 `D j 〈τ〉.By IH, we get Π |Θ1 K4.δΓ1([τi/Ti]pi j).Using lemma C.3 we get δΓ1([τi/Ti]pi′)= [δΓ1(τi)/Ti]pi′ andδΓ1([τi/Ti]pi j)= [δΓ1(τi)/Ti]pi j.Then using (cons) we have Π |Θ1 K4.δΓ1(pi) as required.* Case ∀Ti.pi j ⇒pi′ ∈Θ2: Wlog, let pi′ = τ : D 〈τn〉.From assumptions we have Γ1 `D 〈Ti〉.There is some crate K such thatΠ`K2 vK and Π0K1 vK and ∀Ti.pi j ⇒pi′ ∈ lcenv (Π,K).From consistency of K2, we know pi′ satisfies orphan rules in K2.Specifically, Π`OR K .pi′.200From lemma C.2, we get either:ltenv (Π,K)`D or Π`LT K .τ′ for some τ′ ∈ {τ,τn}.ltenv (Π,K)`D is not possible because ltenv (Π,K)⊆ Γ2 and Γ1 `D and weassume there are no overlapping identifiers between Γ1 and Γ2.If Π`LT K .τ′ for some τ′ ∈ {τ,τn} then by lemma C.9, Π`LT K . [τi/Ti]τ′ andby lemma C.8, δΓ1([τi/Ti]τ′) ∈BLANKETTYPE.Then we can use either rule (blanket1) or (blanket2), depending on the posi-tion of τ′ in pi, to prove Π |Θ1 K4.δΓ1(pi) as required.– Case (blanket1):Simple induction on the structure of B shows that δΓ1(B) ∈BLANKETTYPE for anyB.– Case (blanket2):Same argument as for (blanket1).– Case (orphan):We want to show that if Π `OR K4 ` δΓ1(pi) then Π `OR K4 ` pi, which holds bylemma C.12, so if Π 6`OR K4 `pi then Π 6`OR K4 ` δΓ1(pi).• Case 3: Π`K3 vK4. Analogous to case 2.Theorem 8.3 (Crate extensibility). Let K be a consistent crate under Π whereΠ = Π′′∪ {K : 〈{Ka},ΓK ,ΘK 〉}. Then let Π′ = [K ′/K]Π′′∪ {K ′ : 〈{Ka},ΓK ,ΘK ∪ {θ1}〉} where K ′ isconsistent in Π′ and θ1 = ∀Tk.pi j ⇒ τ1 : D 〈τ1n〉 with τ 6∈ BLANKETTYPE for each τ ∈ {τ1,τ1n}.Then, for each crate K1 such that Π′ ` K1 v K ′, if K1 is consistent under Π, then it is alsoconsistent under Π′.Proof. We prove this by induction on the crate dependency relation, assuming in the induc-tion hypothesis that K2 is consistent for all K2 such that Π′ `K2@K1 (i.e., Π`K2 vK1 andK1 6=K2). The only interesting thing we have to check for is overlap of constraint schemes incenv (Π′,K1). We split the proof into two cases:• Case 1: We want to show that θ1 does not overlap with any other θ2 ∈ lcenv (Π′,K1).The property is already guaranteed if Π′ `K ′ vK1 from the consistency of K ′ under Π′.We then consider the case where Π′ 0K ′ vK1.Let θ2 =∀Tl .pim ⇒ τ2 : D 〈τ2n〉 andlet φ be a type substitution such that φ(τ1 : D 〈τ1n〉)=φ(τ2 : D 〈τ2n〉).From consistency of K1 under Π, τ2 : D 〈τ2n〉 satisfies the orphan rule under Π.By lemma C.14, the constraint also satisfies the orphan rule under Π′.201So either ltenv (Π′,K1)`D or there is some type τ ∈ {τ2,τ2n} s.t. Π′ `LT K1.τ.From lemma C.1 and consistency of K ′ we know thattenv (Π′,K ′)`D and tenv (Π′,K ′)`WF τ′ for each τ′ ∈ {τ2,τ2n}.However, from lemma C.6, tenv (Π′,K ′)`D is not possible.Now suppose wlog that Π′ `LT K1.τ2.Then τ2 =&S 〈τ〉 where S 〈T〉 {. . . } ∈ ltenv (Π′,K2). Since we assumed that φ(τ1)=φ(τ2),either τ1 =&S 〈τ′〉 for some τ′or τ1 =&T for some type variable T.Since Π′ `LT K1.&S 〈τ′〉, we can use lemma C.5 to show that tenv (Π′,K ′) 6`WF &S 〈τ′〉.On the other hand τ1 cannot be equal to &T as &T ∈ BLANKETTYPE and that contra-dicts our initial assumption.The same argument holds for any τ′ ∈ τ2n.Therefore, there is no possible substitution φ such that φ(τ1 : D 〈τ1n〉) = φ(τ2 : D 〈τ2n〉)and so, θ1 and θ2 don’t overlap.• Case 2: We want to show that any θ2,θ3 ∈ cenv (Π,K1) such that θ2 6= θ1 and θ3 6= θ1don’t overlap under Π′ and K1.Suppose some K2,K3 such that θ2 ∈ lcenv (Π′,K2) and θ2 ∈ lcenv (Π′,K3).Using theorem 8.2 we can conclude that if K2 6= K1 and K3 6= K1 then θ2 and θ3 don’toverlap.We must then consider the case where θ2 ∈ lcenv (Π′,K1) and θ3 ∈ lcenv (Π′,K3) forsome K3 6=K1 (the proof for the opposite case is the same).Let θ2 =∀Tl .pim ⇒ τ2 : D′ 〈τ2 p〉 and θ3 =∀Tq.pir ⇒ τ3 : D′ 〈τ3 p〉.Suppose there is a type substitution φ such that φ(τ2 : D′ 〈τ2 p〉)=φ(τ3 : D′ 〈τ3 p〉).Let Θ′ = lcenv (Π′,K1)=Θ∪ {θ1}.We want to show that for every pi ∈ {pim,pir}, if Π′ |Θ′K1.φ(pi)then Π |Θ K1.φ(pi) from which we can derive a contradiction that no such φ existsand that θ2 and θ3 can’t overlap in Π′,Θ′.We proceed by induction on derivations Π′ |Θ′K1.pi′ to show that Π |ΘK1.pi′.The only interesting case is (cons) where pi′ = [τi/Ti]piand ∀Ti.pi j ⇒pi ∈Θ′ and Π′ |Θ′K1. [τi/Ti]pi j.If ∀Ti.pi j ⇒pi ∈Θ then we can use IH to concludeΠ |ΘK1. [τi/Ti]pi j and Π |ΘK1.pi′.On the other hand, consider ∀Ti.pi j ⇒pi= θ1. Then pi= τ1 : D 〈τ1n〉.We will now show that Π 6`OR K1.pi.For contradiction suppose that Π`OR K1.pi.Then, by lemma C.2, either ltenv (Π,K1)`D202or there is some τ ∈ {τ1,τ1n} such that Π`LT K1.τ′.Since we assume that Π`K ′@K1, using lemma C.6 we get ltenv (Π,K1)0D.Also, by lemma C.13 there is no τ ∈ {τ1,τ1n} such that Π`LT K1.τ′.Then we can use (orphan) to prove Π |ΘK1.pi as required.203
Thesis/Dissertation
2016-02
10.14288/1.0220521
eng
Computer Science
Vancouver : University of British Columbia Library
University of British Columbia
Attribution-NonCommercial-NoDerivs 2.5 Canada
http://creativecommons.org/licenses/by-nc-nd/2.5/ca/
Graduate
Formalizing Rust traits
Text
http://hdl.handle.net/2429/55609