Skip to content

Commit fdcd8b7

Browse files
nikomatsakisbrson
authored andcommitted
Fix various typos and add an appdenix motivating the restriction
to exactly one lifetime.
1 parent b72b682 commit fdcd8b7

File tree

1 file changed

+59
-13
lines changed

1 file changed

+59
-13
lines changed

active/0000-bounds-on-object-and-generic-types.md

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
Currently, the type system is not supposed to allow references to
2121
escape into object types. However, there are various bugs where it
22-
fails to prevent this from hapenning. Moreover, it is very useful (and
22+
fails to prevent this from happening. Moreover, it is very useful (and
2323
frequently necessary) to store a reference into an object. Moreover,
2424
the current treatment of generic types is in some cases naive and not
2525
obviously sound.
@@ -105,7 +105,6 @@ Here are some examples:
105105

106106
trait IsStatic : 'static { }
107107
trait Is<'a> : 'a { }
108-
trait IsNothing { }
109108

110109
// Type Bounds
111110
// IsStatic 'static
@@ -124,11 +123,11 @@ default lifetime using the normal rules:
124123
Box<Writer+Send>, // OK: Send implies 'static
125124
&'a Writer, // Error: try &'a (Writer+'a)
126125
}
127-
126+
128127
fn foo(a: Box<Writer>, // OK: Sugar for Box<Writer+'a> where 'a fresh
129-
b: &Writer) // OK: Sugar for &'a (Writer+'b) where 'a, 'b fresh
128+
b: &Writer) // OK: Sugar for &'b (Writer+'c) where 'b, 'c fresh
130129
{ ... }
131-
130+
132131
This kind of annotation can seem a bit tedious when using object types
133132
extensively, though type aliases can help quite a bit:
134133

@@ -138,6 +137,9 @@ extensively, though type aliases can help quite a bit:
138137
The unresolved questions section discussed possibles ways to lighten
139138
the burden.
140139

140+
See Appendix B for the motivation on why object types are permitted to
141+
have exactly one lifetime bound.
142+
141143
## Specifying relations between lifetimes
142144

143145
Currently, when a type or fn has multiple lifetime parameters, there
@@ -155,10 +157,10 @@ them explicitly (and necessary in some cases, see below).
155157
A *lifetime bound* is written `'a:'b` and it means that "`'a` outlives
156158
`'b`". For example, if `foo` were declared like so:
157159

158-
fn foo<'a, 'b:'a>(...) { ... }
160+
fn foo<'x, 'y:'x>(...) { ... }
159161

160-
that would indicate that the lifetime '`a` was shorter than (or equal
161-
to) `'b`.
162+
that would indicate that the lifetime '`x` was shorter than (or equal
163+
to) `'y`.
162164

163165
## The "type must outlive" and well-formedness relation
164166

@@ -229,7 +231,7 @@ The compiler will infer lifetime bounds on both type parameters and
229231
region parameters as follows. Within a function or method, we apply
230232
the wellformedness function `WF` to each function or parameter type.
231233
This yields up a set of relations that must hold. The idea here is
232-
that the caller could have type checked unless the types of the
234+
that the caller could not have type checked unless the types of the
233235
arguments were well-formed, so that implies that the callee can assume
234236
that those well-formedness constraints hold.
235237

@@ -291,7 +293,7 @@ This RFC has a lot of details. The main implications for end users are:
291293
arena: &'global Arena
292294
}
293295
294-
struct LocalConenxt<'local, 'global:'local> {
296+
struct LocalContext<'local, 'global:'local> {
295297
x: &'local mut Context<'global>
296298
}
297299
@@ -345,6 +347,9 @@ traverse the type hierarchy deeply to find its origin. This could
345347
potentially be addressed with better error messages, though our track
346348
record for lifetime error messages is not very good so far.
347349

350+
Also, there is a potential interaction between this sort of inference
351+
and the description of default trait bounds below.
352+
348353
## Default trait bounds
349354

350355
When referencing a trait object, it is almost *always* the case that one follows
@@ -358,12 +363,17 @@ certain fixed patterns:
358363
You might think that we should simply provide some kind of defaults
359364
that are sensitive to where the `Trait` appears. The same is probably
360365
true of struct type parameters (in other words, `&'a SomeStruct<'a>`
361-
is a very comon pattern).
366+
is a very common pattern).
362367

363368
However, there are complications:
364369

365-
- What about a type like `struct Ref<'a, T> { x: &'a T }`? `Ref<'a, Trait>`
366-
should really work the same way as `&'a Trait`.
370+
- What about a type like `struct Ref<'a, T:'a> { x: &'a T }`? `Ref<'a,
371+
Trait>` should really work the same way as `&'a Trait`. One way that
372+
I can see to do this is to drive the defaulting based on the default
373+
trait bounds of the `T` type parameter -- but if we do that, it is
374+
both a non-local default (you have to consult the definition of
375+
`Ref`) and interacts with the potential inference described in the
376+
previous section.
367377
- There *are* reasons to want a type like `Box<Trait+'a>`. For example,
368378
the macro parser includes a function like:
369379

@@ -422,3 +432,39 @@ lifetime `'a` yields a list of `'b:'c` or `X:'d` pairs. For each pair
422432

423433
We can then say that `T outlives 'a` if all lifetime relations
424434
returned by `WF(T:'a)` hold.
435+
436+
# Appendix B: Why object types must have exactly one bound
437+
438+
The motivation is that handling multiple bounds is overwhelmingly
439+
complicated to reason about and implement. In various places,
440+
constraints arise of the form `all i. exists j. R[i] <= R[j]`, where
441+
`R` is a list of lifetimes. This is challenging for lifetime
442+
inference, since there are many options for it to choose from, and
443+
thus inference is no longer a fixed-point iteration. Moreover, it
444+
doesn't seem to add any particular expressiveness.
445+
446+
The places where this becomes important are:
447+
448+
- Checking lifetime bounds when data is closed over into an object type
449+
- Subtyping between object types, which would most naturally be
450+
contravariant in the lifetime bound
451+
452+
Similarly, requiring that the "master" bound on object lifetimes outlives
453+
all other bounds also aids inference. Now, given a type like the
454+
following:
455+
456+
trait Foo<'a> : 'a { }
457+
trait Bar<'b> : 'b { }
458+
459+
...
460+
461+
let x: Box<Foo<'a>+Bar<'b>>
462+
463+
the inference engine can create a fresh lifetime variable `'0` for the
464+
master bound and then say that `'0:'a` and `'0:'b`. Without the
465+
requirement that `'0` be a master bound, it would be somewhat unclear
466+
how `'0` relates to `'a` and `'b` (in fact, there would be no
467+
necessary relation). But if there is no necessary relation, then when
468+
closing over data, one would have to ensure that the closed over data
469+
outlives *all* derivable lifetime bounds, which again creates a
470+
constraint of the form `all i. exists j.`.

0 commit comments

Comments
 (0)