Commit Graph

275 Commits

Author SHA1 Message Date
Doug Gregor
a30ca2a60d Replace bool parameter to TypeChecker::conformsToProtocol() with an option set.
NFC; we can extend this option set more readily later.

Swift SVN r27894
2015-04-29 00:08:22 +00:00
Chris Lattner
6c8e9ac276 change some calls to dyn_cast in boolean contexts to isa.
Swift SVN r27724
2015-04-25 23:34:38 +00:00
Chris Lattner
d18740d603 Fix <rdar://problem/19773562> Closures executed immediately { like this }() are not automatically @noescape
In addition to being better for performance in these cases, this disables the "self." 
requirement in these blocks.  {}() constructs are often used to work around statements
that are not exprs in Swift, so they are reasonably important.

Fixing this takes a couple of pieces working together:
 - Add a new 'extraFunctionAttrs' map to the ConstraintSystem for solution
   invariant function attributes that are inferred (like @noescape).
 - Teach constraint simplification of function applications to propagate 
   @noescape between unified function types.
 - Teach CSGen of ApplyExprs to mark the callee functiontype as noescape
   when it is obviously a ClosureExpr.

This is a very limited fix in some ways: you could argue that ApplyExpr should
*always* mark its callee as noescape.  However, doing so would just introduce a
ton of function conversions to remove it again, so we don't do that.




Swift SVN r27723
2015-04-25 23:34:18 +00:00
Joe Pamer
d4e744b2ed Use "isa" instead of "dyn_cast".
Swift SVN r27606
2015-04-22 21:35:57 +00:00
Joe Pamer
220c92a09b Revert "Revert "A couple of 'throws' inference fix-ups:""
This reverts commit r27576.

(In some cases of catastrophic error recovery, ctor types may still be null during constraint solving, so it was wrong of me to assume otherwise.)

Swift SVN r27599
2015-04-22 20:34:05 +00:00
Dmitri Hrybenko
4229e8a14f Revert "A couple of 'throws' inference fix-ups:"
This reverts commit r27568 to unblock the buildbot.  It regressed three
compiler crashers:

    Swift :: compiler_crashers_fixed/0367-llvm-errs.swift
    Swift :: compiler_crashers_fixed/1769-getselftypeforcontainer.swift
    Swift :: compiler_crashers_fixed/1916-swift-nominaltypedecl-getdeclaredtypeincontext.swift

Swift SVN r27576
2015-04-22 08:42:21 +00:00
Joe Pamer
70fd1d6360 A couple of 'throws' inference fix-ups:
- When inferring 'throws' for a closure function type, look inside of catchless do blocks for 'try' expressions.
- When simplifying overload constriants for applications of throwing initializers, the bound member type of the initializer should also be marked as throwing.
  (Not doing so would cause us to incorrectly reject the overload.)

Swift SVN r27568
2015-04-22 06:39:39 +00:00
Chris Willmore
d4db635e3d Add object literal syntax and _{Color,Image}LiteralConvertible protocols
Add syntax "[#Color(...)#]" for object literals, to be used by
Playgrounds for inline color wells etc. The arguments are forwarded to
the relevant constructor (although we will probably change this soon,
since (colorLiteralRed:... blue:... green:... alpha) is kind of
verbose). Add _ColorLiteralConvertible and _ImageLiteralConvertible
protocols, and link them to the new expressions in the type checker.
CSApply replaces the object literal expressions with a call to the
appropriate protocol witness.

Swift SVN r27479
2015-04-20 12:55:56 +00:00
Joe Pamer
006c182c13 Begin inferring throwing function types for closures. (There's more work to do here - hence the thin tests - but I need to investigate a couple of sema bugs before moving forward.)
Swift SVN r27438
2015-04-17 19:06:52 +00:00
Joe Pamer
e4f7fee4f4 When gathering "linked" expressions to determine a favored constraint, consider top-level literals to be fair game.
This unblocks standard library work by preventing us from going exponential when extending existing struct types to have failable initializers. (rdar://problem/20336356)
On my laptop, it also results in a 7% end-to-end improvement in the time it takes to run our unit tests under DebugAssert (previously: 591.63s, now: 552.64s). Though, as usual, YMMV.

Swift SVN r27156
2015-04-09 01:54:34 +00:00
Chris Lattner
79ed57f9f2 standardize naming of tuples and tuple patterns on "elements".
Previously some parts of the compiler referred to them as "fields",
and most referred to them as "elements".  Use the more generic 'elements'
nomenclature because that's what we refer to other things in the compiler
(e.g. the elements of a bracestmt).

At the same time, make the API better by providing "getElement" consistently
and using it, instead of getElements()[i].

NFC.



Swift SVN r26894
2015-04-02 20:23:49 +00:00
Chris Lattner
f7fe8a5f4a Fix <rdar://problem/20392122> Destructuring tuple with labels doesn't work
This pushes tuple pattern labels forward:
  - Actually record them in TuplePatternElt.
  - Remove the tuple shuffle ban that prevents some cases
    (e.g. the one in the radar) of a tuple with labels being shuffled
    onto a tuple without labels.
  - Remove dead code enabled by removing the restriction.



Swift SVN r26852
2015-04-02 04:23:54 +00:00
John McCall
08d3460a19 Implement throw expressions. Untested.
Tests tomorrow for this and 'catch', I promise. :)

Swift SVN r26432
2015-03-23 08:10:15 +00:00
Argyrios Kyrtzidis
68bd67fc12 [Parse/AST] Introduce an AST node for editor placeholders in expression contexts.
If the placeholder is a typed one, parse its type string into a TypeRepr,
resolve it during typechecking and set it as the type for the associated EditorPlaceholderExpr.

Swift SVN r26215
2015-03-17 01:53:02 +00:00
Chris Lattner
20f8f09ea8 Land: <rdar://problem/19382905> improve 'if let' to support refutable patterns and untie it from optionals
This changes 'if let' conditions to take general refutable patterns, instead of
taking a irrefutable pattern and implicitly matching against an optional.

Where before you might have written:
  if let x = foo() {

you now need to write:
  if let x? = foo() {
    
The upshot of this is that you can write anything in an 'if let' that you can
write in a 'case let' in a switch statement, which is pretty general.

To aid with migration, this special cases certain really common patterns like
the above (and any other irrefutable cases, like "if let (a,b) = foo()", and
tells you where to insert the ?.  It also special cases type annotations like
"if let x : AnyObject = " since they are no longer allowed.

For transitional purposes, I have intentionally downgraded the most common
diagnostic into a warning instead of an error.  This means that you'll get:

t.swift:26:10: warning: condition requires a refutable pattern match; did you mean to match an optional?
if let a = f() {
       ^
        ?

I think this is important to stage in, because this is a pretty significant
source breaking change and not everyone internally may want to deal with it
at the same time.  I filed 20166013 to remember to upgrade this to an error.

In addition to being a nice user feature, this is a nice cleanup of the guts
of the compiler, since it eliminates the "isConditional()" bit from
PatternBindingDecl, along with the special case logic in the compiler to handle
it (which variously added and removed Optional around these things).




Swift SVN r26150
2015-03-15 07:06:22 +00:00
Chris Lattner
90920ec02f rename the IsaExpr AST node to IsExpr to follow the syntax of the language, NFC.
Swift SVN r25933
2015-03-10 17:11:37 +00:00
Doug Gregor
3805e18090 Explicitly track the mapping from dependent types to their opened type variables.
Previously, we were reconstructing this mapping from the "full" opened
type produced by declaration references. However, when dealing with
same-type constraints between associated types and type parameters, we
could end up with an incomplete mapping, which let archetypes slip
through. Most of the churn here is sorting out the locators we need to
use to find the opened-type information. Fixes rdar://problem/18208283
and at least 3 dupes of it that I've found so far.

Swift SVN r25375
2015-02-18 19:41:40 +00:00
Joe Pamer
ec6810827a Replace a dyn_cast to "DictionaryType" with an invocation of ConstraintSystem::isDictionaryType. (I'm pretty sure that just relying on the cast can cause problems when generating constraints.)
Swift SVN r25157
2015-02-11 01:25:33 +00:00
Joe Pamer
c5c521392e Don't over-eagerly specialize the return type of an enum initializer application. Doing so doesn't really improve compiler throughput, but can cause problems if the enum has overloaded initializers. (rdar://problem/19697319)
Swift SVN r25147
2015-02-11 00:13:16 +00:00
Joe Pamer
9923e3ff89 When optimizing constraints for an unresolved dot expression, don't walk into the base expression - it will most likely result in an incorrect favored type, which can lead to "expression too complex" errors. (rdar://problem/19773442, rdar://problem/19770646)
Swift SVN r25129
2015-02-10 19:14:29 +00:00
Chris Willmore
e2ac9f65ac Add FixKind for 'as' -> 'as!' conversion
Penalize solutions that involve 'as' -> 'as!' changes by recording a Fix
when simplifying the corresponding checked-cast constraint.

<rdar://problem/19724719> Type checker thinks "(optionalNSString ?? nonoptionalNSString) as String" is a forced cast

Swift SVN r25061
2015-02-07 00:33:37 +00:00
Joe Pamer
45e7fd53dd Remove a misguided peephole optimization from the constraint generator. This fix partially unblocks the build of the Cartography external project.
Swift SVN r24927
2015-02-03 21:15:00 +00:00
Chris Willmore
ab86515fb2 <rdar://problem/19671476> Offer as -> as! changes in all nested contexts
When generating constraints for an 'as' expression, consider the
possibility that the code is supposed to be 'as!' instead of 'as'. Emit
the appropriate fixit if that branch of the disjunction is chosen by the
constraint solver.

This is a more comprehensive fix for <rdar://problem/19499340> than the
one in r24815.

Swift SVN r24872
2015-01-31 00:55:53 +00:00
Joe Pamer
a18bedf079 Factor the constraint-favoring machinery out of the constraint generation process, and re-work it into a series of passes over an expression sub-tree.
Aside from tidying things up, doing this results in some significant benefits:
- Allows for global constraint ordering optimizations over a given expression, not just on a peephole basis.
- Eliminates a set of order-dependent bugs in the solver that have been dogging us for a while. (rdar://problem/19459079)
- Brings another set of tyvar-to-tyvar solving problems out of the realm of the exponential. (rdar://problem/19005271)
- Opens up the possibility of optimizing constraints during later solving phases - not just while generating them.

Swift SVN r24693
2015-01-23 23:10:50 +00:00
Joe Pamer
ea7bd2de53 Per Doug's comment, check for failable initializers on enum types when optimizing the return type of an initializer application. With this change, Adventure builds cleanly once again.
Swift SVN r24595
2015-01-21 06:10:41 +00:00
Joe Pamer
d9325547e5 Favor dictionary subscript return types (in addition to array subscript return types).
Swift SVN r24523
2015-01-19 20:59:15 +00:00
Joe Pamer
f453bceeb1 Fix utilization of expected types for subscript and apply expressions when favoring constraints. (rdar://problem/19334553)
Swift SVN r24522
2015-01-19 20:59:15 +00:00
Joe Pamer
35184ff7b5 Utilize argument type information to favor overload binding constraints on initializers. Doing so addresses a number of cases where the type checker was going exponential on seemingly simple user code.
Also, these changes fix the performance regressions that were introduced as a result of September's convertible/init requirement modifications, and allow us to roll back the associated workarounds that were added to the Adventure sample (rdar://problem/18942100).

Swift SVN r24520
2015-01-19 20:59:14 +00:00
Joe Pamer
f56949846f Propagate constraint favoring information across nodes of chained operations. This allows us to properly favor constraints for expressions the form "(float0 + float1) * float2".
Swift SVN r24519
2015-01-19 20:59:14 +00:00
Joe Pamer
87be8b13b7 Only favor overload constraints on OverloadedDeclRefs with distinct numbers of parameters. This allows us to keep the previous optimization, while still preserving ambiguity diagnostics.
Swift SVN r24518
2015-01-19 20:59:13 +00:00
Joe Pamer
da7e63cc24 For closure and subscript expressions, if valid contextual information is available use it instead of allocating type variables for their result types.
Swift SVN r24516
2015-01-19 20:59:12 +00:00
Joe Pamer
885ef0de5f When generating constraints for an application of an overloaded function, if all overloads share a common return type, use that type rather than allocating a new type variable.
Swift SVN r24515
2015-01-19 20:59:12 +00:00
Joe Pamer
87cbad9ec1 Improve performance of solving over apply expressions by directly applying the return type whenever possible. This has some nice side-effects:
- Addresses many common user-reported "expression too complex" bugs, including rdar://problem/18876786.
- Shaves up to 10% off of the total time to run our unit tests. (Unscientifically measured on my iMac: 427.46s before, 385.17s after.)

Swift SVN r24514
2015-01-19 20:59:11 +00:00
Chris Willmore
68dd563fbf <rdar://problem/18311362> TLF: Eliminate implicit bridging conversions
Require 'as' when converting from Objective-C type to native type (but
continue to allow implicit conversion from native to Objective-C). This
conversion constraint is called ExplicitConversion; all implicit
conversions are covered by the existing Conversion constraint. Update
standard library and tests to match.

Swift SVN r24496
2015-01-18 00:07:45 +00:00
Chris Willmore
03a6190a1f <rdar://problem/19031957> Change failable casts from "as" to "as!"
Previously the "as" keyword could either represent coercion or or forced
downcasting. This change separates the two notions. "as" now only means
type conversion, while the new "as!" operator is used to perform forced
downcasting. If a program uses "as" where "as!" is called for, we emit a
diagnostic and fixit.

Internally, this change removes the UnresolvedCheckedCastExpr class, in
favor of directly instantiating CoerceExpr when parsing the "as"
operator, and ForcedCheckedCastExpr when parsing the "as!" operator.

Swift SVN r24253
2015-01-08 00:33:59 +00:00
Joe Pamer
2912159776 Improve diagnostics for expression typecheck errors
These changes make the following improvements to how we generate diagnostics for expression typecheck failure:
- Customizing a diagnostic for a specific expression kind is as easy as adding a new method to the FailureDiagnosis class,
  and does not require intimate knowledge of the constraint solver’s inner workings.
    - As part of this patch, I’ve introduced specialized diagnostics for call, binop, unop, subscript, assignment and inout
      expressions, but we can go pretty far with this.
    - This also opens up the possibility to customize diagnostics not just for the expression kind, but for the specific types
      involved as well.
- For the purpose of presenting accurate type info, partially-specialized subexpressions are individually re-typechecked
  free of any contextual types. This allows us to:
    - Properly surface subexpression errors.
    - Almost completely avoid any type variables in our diagnostics. In cases where they could not be eliminated, we now
      substitute in "_".
    - More accurately indicate the sources of errors.
- We do a much better job of diagnosing disjunction failures. (So no more nonsensical ‘UInt8’ error messages.)
- We now present reasonable error messages for overload resolution failures, informing the user of partially-matching
  parameter lists when possible.

At the very least, these changes address the following bugs:

<rdar://problem/15863738> More information needed in type-checking error messages
<rdar://problem/16306600> QoI: passing a 'let' value as an inout results in an unfriendly diagnostic
<rdar://problem/16449805> Wrong error for struct-to-protocol downcast
<rdar://problem/16699932> improve type checker diagnostic when passing Double to function taking a Float
<rdar://problem/16707914> fatal error: Can't unwrap Optional.None…Optional.swift, line 75 running Master-Detail Swift app built from template
<rdar://problem/16785829> Inout parameter fixit
<rdar://problem/16900438> We shouldn't leak the internal type placeholder
<rdar://problem/16909379> confusing type check diagnostics
<rdar://problem/16951521> Extra arguments to functions result in an unhelpful error
<rdar://problem/16971025> Two Terrible Diagnostics
<rdar://problem/17007804> $T2 in compiler error string
<rdar://problem/17027483> Terrible diagnostic
<rdar://problem/17083239> Mysterious error using find() with Foundation types
<rdar://problem/17149771> Diagnostic for closure with no inferred return value leaks type variables
<rdar://problem/17212371> Swift poorly-worded error message when overload resolution fails on return type
<rdar://problem/17236976> QoI: Swift error for incorrectly typed parameter is confusing/misleading
<rdar://problem/17304200> Wrong error for non-self-conforming protocols
<rdar://problem/17321369> better error message for inout protocols
<rdar://problem/17539380> Swift error seems wrong
<rdar://problem/17559593> Bogus locationless "treating a forced downcast to 'NSData' as optional will never produce 'nil'" warning
<rdar://problem/17567973> 32-bit error message is really far from the mark: error: missing argument for parameter 'withFont' in call
<rdar://problem/17671058> Wrong error message: "Missing argument for parameter 'completion' in call"
<rdar://problem/17704609> Float is not convertible to UInt8
<rdar://problem/17705424> Poor error reporting for passing Doubles to NSColor: extra argument 'red' in call
<rdar://problem/17743603> Swift compiler gives misleading error message in "NSLayoutConstraint.constraintsWithVisualFormat("x", options: 123, metrics: nil, views: views)"
<rdar://problem/17784167> application of operator to generic type results in odd diagnostic
<rdar://problem/17801696> Awful diagnostic trying to construct an Int when .Int is around
<rdar://problem/17863882> cannot convert the expression's type '()' to type 'Seq'
<rdar://problem/17865869> "has different argument names" diagnostic when parameter defaulted-ness differs
<rdar://problem/17937593> Unclear error message for empty array literal without type context
<rdar://problem/17943023> QoI: compiler displays wrong error when a float is provided to a Int16 parameter in init method
<rdar://problem/17951148> Improve error messages for expressions inside if statements by pre-evaluating outside the 'if'
<rdar://problem/18057815> Unhelpful Swift error message
<rdar://problem/18077468> Incorrect argument label for insertSubview(...)
<rdar://problem/18079213> 'T1' is not identical to 'T2' lacks directionality
<rdar://problem/18086470> Confusing Swift error message: error: 'T' is not convertible to 'MirrorDisposition'
<rdar://problem/18098995> QoI: Unhelpful compiler error when leaving off an & on an inout parameter
<rdar://problem/18104379> Terrible error message
<rdar://problem/18121897> unexpected low-level error on assignment to immutable value through array writeback
<rdar://problem/18123596> unexpected error on self. capture inside class method
<rdar://problem/18152074> QoI: Improve diagnostic for type mismatch in dictionary subscripting
<rdar://problem/18242160> There could be a better error message when using [] instead of [:]
<rdar://problem/18242812> 6A1021a : Type variable leaked
<rdar://problem/18331819> Unclear error message when trying to set an element of an array constant (Swift)
<rdar://problem/18414834> Bad diagnostics example
<rdar://problem/18422468> Calculation of constant value yields unexplainable error
<rdar://problem/18427217> Misleading error message makes debugging difficult
<rdar://problem/18439742> Misleading error: "cannot invoke" mentions completely unrelated types as arguments
<rdar://problem/18535804> Wrong compiler error from swift compiler
<rdar://problem/18567914> Xcode 6.1. GM, Swift, assignment from Int64 to NSNumber. Warning shown as problem with UInt8
<rdar://problem/18784027> Negating Int? Yields Float
<rdar://problem/17691565> attempt to modify a 'let' variable with ++ results in typecheck error about @lvalue Float
<rdar://problem/17164001> "++" on let value could give a better error message

Swift SVN r23782
2014-12-08 21:56:47 +00:00
Chris Lattner
f3ed7e93e1 Completely redesign our AST representation of capturelists. Formerly,
a capture list hung off the CaptureExpr it was associated with.  This made
sense lexically (since a capture list is nested inside of the closure) but
not semantically.  Semantically, the capture list initializers are evaluated
outside the closure, the variables are bound to those values, then the closure
captures the newly bound values.

To directly represent this, represent captures with a new CaptureListExpr node,
which contains the ClosureExpr inside of it.  This correctly models the semantic
relationship, and makes sure that AST walkers all process the initializers of the
capture list as being *outside* of the closure.

This fixes rdar://19146761 and probably others.


Swift SVN r23756
2014-12-06 04:36:11 +00:00
Jordan Rose
2b0fbcbe80 Looking up conformances for a type isn't always a public use of the type.
Specifically, it's not when
- the conformance is being used within a function body (test included)
- the conformance is being used for or within a private type (test included)
- the conformance is being used to generate a diagnostic string

We're still a bit imprecise in some places (checking ObjC bridging), but
in general this means less of an issue for checking literals.

Swift SVN r23700
2014-12-05 00:23:24 +00:00
Jordan Rose
d1c5c5ddac Dependencies: Not all identifier types are non-private dependencies.
This commit treats all TypeExprs and casts as private if the decl context
is a function. In other cases we fall back to the general rules about the
current context (from r23447).

Swift SVN r23522
2014-11-21 19:32:16 +00:00
Chris Willmore
b9d86b0275 Remove lvalue-bindable bit from type variables for function parameters.
rdar://problem/18571392

Swift SVN r22877
2014-10-22 23:01:39 +00:00
Devin Coughlin
2e3acba163 Add availability checking for properties to Sema
This commit adds availability checking for properties to Sema. When
EnableExperimentalAvailabilityChecking is enabled, we now emit a diagnostic
when a potentially unavailable property is accessed. To support this, we
now build type refinement contexts for most ValueDecls.


Swift SVN r22622
2014-10-09 17:21:52 +00:00
Jordan Rose
042569a3be Optional: Replace uses of Nothing with None.
llvm::Optional (like Swift.Optional!) uses None as its placeholder value,
not Nothing.

Swift SVN r22476
2014-10-02 18:51:42 +00:00
Devin Coughlin
2e8d4bc718 Add handling of potentially unavailable overloaded global functions to Sema.
This commit also factors out some common checking and diagnostic code; it
additionally moves diagnostic emission for unavailable references from CSGen to
CSApply.


Swift SVN r22447
2014-10-01 23:52:08 +00:00
Devin Coughlin
3749a98763 Record the reason a declaration is potentially unavailable.
This commit adds tracking of the reason a declaration reference is potentially
unavailable to the UnavailableToOptionalExpr AST node and to OverloadChoice. We
will use this reason during SILGen to emit the appropriate run-time check and
during typechecking to provide more helpful diagnostics.

To keep OverloadChoice as small as possible, we encode the reason as an index
into a vector of reasons stored in a given instance of ConstraintSystem (this is
the same approach that Fix takes).

This commit adds Sema/OverloadChoice.cpp (for the parts of OverloadChoice that
now rely on ConstraintSystem) and AST/Availability.h (to bring in
availability-related structures without TypeRefinementContext).


Swift SVN r22377
2014-09-30 01:53:59 +00:00
Devin Coughlin
b727b6d932 Treat potentially unavailable global variable references as optional.
This patch adds the ability (-enable-experimental-unavailable-as-optional) to
treat potentially unavailable declarations as if they had optional types. For
the moment, this is only implemented for global variables.

The high-level approach is to (1) record the potential unavailability of a
declaration reference in the overload choice during constraint generation; (2)
treat the declaration as if it had an optional type during overload resolution
(this is similar to how optional protocol members are treated); and (3) add an
implicit conversion (UnavailableToOptionalExpr) during constraint application
to represent the run-time availability check and optional injection.

This patch does not implement SILGen for UnavailableToOptionalExpr.


Swift SVN r22245
2014-09-24 00:07:46 +00:00
Doug Gregor
df33350219 Switch string interpolation protocol over to initializer requirements.
With this, we're now using initializer requirements rather than
"convertFromXXX" requirements everywhere, addressing the rest of
rdar://problem/18154091. r22176 eliminated the performance penalty
that prevented this change from sticking earlier.



Swift SVN r22177
2014-09-22 20:17:55 +00:00
Doug Gregor
55afb33c94 Associate argument labels with the callee in the solver.
When performing name lookup for a declaration that is being called,
use the argument labels at the call site to filter out those
declarations with incompatible argument labels.


Swift SVN r22176
2014-09-22 20:08:01 +00:00
Doug Gregor
771266dd98 Favor unary operators with matching argument/contextual type.
This is only a small performance win (1-2%) in our own testsuite, but
fits easily into the generalized favored-constraints handling.



Swift SVN r22172
2014-09-22 14:21:26 +00:00
Doug Gregor
8b4a5b43a9 Generalize the favored-constraint handling code for calls.
Split the binary-operator favored-constraint optimization code into a
general part, which handles the construction of the disjunctions for a
favored set of constraints, and the binary-operator part, that
implements the existing optimization. NFC, but should make it easier
to perform similar optimizations in the future.


Swift SVN r22171
2014-09-22 14:09:41 +00:00
Doug Gregor
4db2974fb7 Refactor the favored-constraints optimization for binary expressions.
Pull the favored-constraints optimization for binary expressions out
into its own function. Use early exits to de-nest the code a few
levels, eliminate some dead code paths that couldn't actually occur,
replace a dyn_cast/.getPointer() dance with getAs<>, and and avoid
excess SmallVector traffic by only copying the "old" constraints in
cases where we might be added new ones (e.g., due to the synthesized
==). NFC



Swift SVN r22170
2014-09-22 13:42:43 +00:00