text:
//===--- ParseType.cpp - Swift Language Parser for Types ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Type Parsing and AST Building
//
//===----------------------------------------------------------------------===//

#include "swift/Parse/Parser.h"
#include "swift/AST/Attr.h"
#include "swift/AST/TypeLoc.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/SaveAndRestore.h"
using namespace swift;

TypeRepr *Parser::applyAttributeToType(TypeRepr *ty,
                                       const TypeAttributes &attrs) {
  // Apply those attributes that do apply.
  if (attrs.empty())
    return ty;

  return new (Context) AttributedTypeRepr(attrs, ty);
}

ParserResult<TypeRepr> Parser::parseTypeSimple() {
  return parseTypeSimple(diag::expected_type);
}

/// parseTypeSimple
///   type-simple:
///     type-identifier
///     type-tuple
///     type-composition
///     'Any'
///     type-simple '.Type'
///     type-simple '.Protocol'
///     type-simple '?'
///     type-simple '!'
///     type-collection
ParserResult<TypeRepr> Parser::parseTypeSimple(Diag<> MessageID,
                                               bool HandleCodeCompletion) {
  ParserResult<TypeRepr> ty;
  // If this is an "inout" marker for an identifier type, consume the inout.
  SourceLoc InOutLoc;
  consumeIf(tok::kw_inout, InOutLoc);

  switch (Tok.getKind()) {
  case tok::kw_Self:
    ty = parseTypeIdentifier();
    break;
  case tok::identifier:
  case tok::kw_protocol:
  case tok::kw_Any:
    ty = parseTypeIdentifierOrTypeComposition();
    break;
  case tok::l_paren:
    ty = parseTypeTupleBody();
    break;
  case tok::code_complete:
    if (!HandleCodeCompletion)
      break;
    if (CodeCompletion)
      CodeCompletion->completeTypeSimpleBeginning();
    // Eat the code completion token because we handled it.
    consumeToken(tok::code_complete);
    return makeParserCodeCompletionResult<TypeRepr>();
  case tok::kw_super:
  case tok::kw_self:
    // These keywords don't start a decl or a statement, and thus should be
    // safe to skip over.
    diagnose(Tok, MessageID);
    ty = makeParserErrorResult(new (Context) ErrorTypeRepr(Tok.getLoc()));
    consumeToken();
    // FIXME: we could try to continue to parse.
    return ty;
  case tok::l_square:
    ty = parseTypeCollection();
    break;
  default:
    checkForInputIncomplete();
    diagnose(Tok, MessageID);
    return nullptr;
  }

  // '.Type', '.Protocol', '?', and '!' still leave us with type-simple.
  while (ty.isNonNull()) {
    if ((Tok.is(tok::period) || Tok.is(tok::period_prefix))) {
      if (peekToken().isContextualKeyword("Type")) {
        consumeToken();
        SourceLoc metatypeLoc = consumeToken(tok::identifier);
        ty = makeParserResult(ty,
          new (Context) MetatypeTypeRepr(ty.get(), metatypeLoc));
        continue;
      }
      if (peekToken().isContextualKeyword("Protocol")) {
        consumeToken();
        SourceLoc protocolLoc = consumeToken(tok::identifier);
        ty = makeParserResult(ty,
          new (Context) ProtocolTypeRepr(ty.get(), protocolLoc));
        continue;
      }
    }

    if (!Tok.isAtStartOfLine()) {
      if (isOptionalToken(Tok)) {
        ty = parseTypeOptional(ty.get());
        continue;
      }
      if (isImplicitlyUnwrappedOptionalToken(Tok)) {
        ty = parseTypeImplicitlyUnwrappedOptional(ty.get());
        continue;
      }
    }
    break;
  }

  // If we parsed an inout modifier, prepend it.
  if (InOutLoc.isValid())
    ty = makeParserResult(new (Context) InOutTypeRepr(ty.get(),
                                                      InOutLoc));

  return ty;
}

ParserResult<TypeRepr> Parser::parseType() {
  return parseType(diag::expected_type);
}

/// parseType
///   type:
///     attribute-list type-function
///     attribute-list type-array
///
///   type-function:
///     type-simple '->' type
///
ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
                                         bool HandleCodeCompletion) {
  // Parse attributes.
  TypeAttributes attrs;
  parseTypeAttributeList(attrs);

  // Parse Generic Parameters. Generic Parameters are visible in the function
  // body.
  GenericParamList *generics = nullptr;
  if (isInSILMode()) {
    generics = maybeParseGenericParams().getPtrOrNull();
  }

  ParserResult<TypeRepr> ty = parseTypeSimple(MessageID, HandleCodeCompletion);
  if (ty.hasCodeCompletion())
    return makeParserCodeCompletionResult<TypeRepr>();

  if (ty.isNull())
    return nullptr;

  // Parse a throws specifier.  'throw' is probably a typo for 'throws',
  // but in local contexts we could just be at the end of a statement,
  // so we need to check for the arrow.
  ParserPosition beforeThrowsPos;
  SourceLoc throwsLoc;
  bool rethrows = false;
  if (Tok.isAny(tok::kw_throws, tok::kw_rethrows) ||
      (Tok.is(tok::kw_throw) && peekToken().is(tok::arrow))) {
    if (Tok.is(tok::kw_throw)) {
      diagnose(Tok.getLoc(), diag::throw_in_function_type)
        .fixItReplace(Tok.getLoc(), "throws");
    }

    beforeThrowsPos = getParserPosition();
    rethrows = Tok.is(tok::kw_rethrows);
    throwsLoc = consumeToken();
  }

  // Handle type-function if we have an arrow.
  SourceLoc arrowLoc;
  if (consumeIf(tok::arrow, arrowLoc)) {
    ParserResult<TypeRepr> SecondHalf =
      parseType(diag::expected_type_function_result);
    if (SecondHalf.hasCodeCompletion())
      return makeParserCodeCompletionResult<TypeRepr>();
    if (SecondHalf.isNull())
      return nullptr;
    if (rethrows) {
      // 'rethrows' is only allowed on function declarations for now.
      diagnose(throwsLoc, diag::rethrowing_function_type);
    }
    auto fnTy = new (Context) FunctionTypeRepr(generics, ty.get(),
                                               throwsLoc,
                                               arrowLoc,
                                               SecondHalf.get());
    return makeParserResult(applyAttributeToType(fnTy, attrs));
  } else if (throwsLoc.isValid()) {
    // Don't consume 'throws', so we can emit a more useful diagnostic when
    // parsing a function decl.
    restoreParserPosition(beforeThrowsPos);
    return ty;
  }

  // Only function types may be generic.
  if (generics) {
    auto brackets = generics->getSourceRange();
    diagnose(brackets.Start, diag::generic_non_function);
  }

  // Parse legacy array types for migration.
  while (ty.isNonNull() && !Tok.isAtStartOfLine()) {
    if (Tok.is(tok::l_square)) {
      ty = parseTypeArray(ty.get());
    } else {
      break;
    }
  }

  if (ty.isNonNull() && !ty.hasCodeCompletion()) {
    ty = makeParserResult(applyAttributeToType(ty.get(), attrs));
  }
  return ty;
}

ParserResult<TypeRepr> Parser::parseTypeIdentifierWithRecovery(
    Diag<> MessageID, Diag<TypeLoc> NonIdentifierTypeMessageID) {
  ParserResult<TypeRepr> Ty = parseType(MessageID);

  if (!Ty.isParseError() && !isa<IdentTypeRepr>(Ty.get()) &&
      !isa<ErrorTypeRepr>(Ty.get())) {
    diagnose(Ty.get()->getStartLoc(), NonIdentifierTypeMessageID, Ty.get())
        .highlight(Ty.get()->getSourceRange());
    Ty.setIsParseError();
    Ty = makeParserResult(
        Ty, new (Context) ErrorTypeRepr(Ty.get()->getSourceRange()));
  }

  assert(Ty.isNull() ||
         isa<IdentTypeRepr>(Ty.get()) ||
         isa<ErrorTypeRepr>(Ty.get()));
  return Ty;
}

bool Parser::parseGenericArguments(SmallVectorImpl<TypeRepr*> &Args,
                                   SourceLoc &LAngleLoc,
                                   SourceLoc &RAngleLoc) {
  // Parse the opening '<'.
  assert(startsWithLess(Tok) && "Generic parameter list must start with '<'");
  LAngleLoc = consumeStartingLess();

  do {
    ParserResult<TypeRepr> Ty = parseType(diag::expected_type);
    if (Ty.isNull() || Ty.hasCodeCompletion()) {
      // Skip until we hit the '>'.
      RAngleLoc = skipUntilGreaterInTypeList();
      return true;
    }

    Args.push_back(Ty.get());
    // Parse the comma, if the list continues.
  } while (consumeIf(tok::comma));

  if (!startsWithGreater(Tok)) {
    checkForInputIncomplete();
    diagnose(Tok, diag::expected_rangle_generic_arg_list);
    diagnose(LAngleLoc, diag::opening_angle);

    // Skip until we hit the '>'.
    RAngleLoc = skipUntilGreaterInTypeList();
    return true;
  } else {
    RAngleLoc = consumeStartingGreater();
  }

  return false;
}

/// parseTypeIdentifier
///
///   type-identifier:
///     identifier generic-args? ('.' identifier generic-args?)*
///
ParserResult<TypeRepr> Parser::parseTypeIdentifier() {
  if (Tok.isNot(tok::identifier) && Tok.isNot(tok::kw_Self)) {
    // is this the 'Any' type
    if (Tok.is(tok::kw_Any)) {
      return parseAnyType();
    } else if (Tok.is(tok::code_complete)) {
      if (CodeCompletion)
        CodeCompletion->completeTypeSimpleBeginning();
      // Eat the code completion token because we handled it.
      consumeToken(tok::code_complete);
      return makeParserCodeCompletionResult<IdentTypeRepr>();
    }

    diagnose(Tok, diag::expected_identifier_for_type);

    // If there is a keyword at the start of a new line, we won't want to
    // skip it as a recovery but rather keep it.
    if (Tok.isKeyword() && !Tok.isAtStartOfLine())
      consumeToken();

    return nullptr;
  }

  ParserStatus Status;
  SmallVector<ComponentIdentTypeRepr *, 4> ComponentsR;
  SourceLoc EndLoc;
  while (true) {
    SourceLoc Loc;
    Identifier Name;
    if (Tok.is(tok::kw_Self)) {
      Loc = consumeIdentifier(&Name);
    } else {
      // FIXME: specialize diagnostic for 'Type': type cannot start with
      // 'metatype'
      // FIXME: offer a fixit: 'self' -> 'Self'
      if (parseIdentifier(Name, Loc, diag::expected_identifier_in_dotted_type))
        Status.setIsParseError();
    }

    if (Loc.isValid()) {
      SourceLoc LAngle, RAngle;
      SmallVector<TypeRepr*, 8> GenericArgs;
      if (startsWithLess(Tok)) {
        if (parseGenericArguments(GenericArgs, LAngle, RAngle))
          return nullptr;
      }
      EndLoc = Loc;

      ComponentIdentTypeRepr *CompT;
      if (!GenericArgs.empty())
        CompT = new (Context) GenericIdentTypeRepr(Loc, Name,
                                             Context.AllocateCopy(GenericArgs),
                                             SourceRange(LAngle, RAngle));
      else
        CompT = new (Context) SimpleIdentTypeRepr(Loc, Name);
      ComponentsR.push_back(CompT);
    }

    // Treat 'Foo.<anything>' as an attempt to write a dotted type
    // unless <anything> is 'Type'.
    if ((Tok.is(tok::period) || Tok.is(tok::period_prefix))) {
      if (peekToken().is(tok::code_complete)) {
        Status.setHasCodeCompletion();
        break;
      }
      if (!peekToken().isContextualKeyword("Type")
          && !peekToken().isContextualKeyword("Protocol")) {
        consumeToken();
        continue;
      }
    } else if (Tok.is(tok::code_complete)) {
      if (!Tok.isAtStartOfLine())
        Status.setHasCodeCompletion();
      break;
    }
    break;
  }

  IdentTypeRepr *ITR = nullptr;
  if (!ComponentsR.empty()) {
    // Lookup element #0 through our current scope chains in case it is some
    // thing local (this returns null if nothing is found).
    if (auto Entry = lookupInScope(ComponentsR[0]->getIdentifier()))
      if (isa<TypeDecl>(Entry))
        ComponentsR[0]->setValue(Entry);

    ITR = IdentTypeRepr::create(Context, ComponentsR);
  }

  if (Status.hasCodeCompletion() && CodeCompletion) {
    if (Tok.isNot(tok::code_complete)) {
      // We have a dot.
      consumeToken();
      CodeCompletion->completeTypeIdentifierWithDot(ITR);
    } else {
      CodeCompletion->completeTypeIdentifierWithoutDot(ITR);
    }
    // Eat the code completion token because we handled it.
    consumeToken(tok::code_complete);
  }

  return makeParserResult(Status, ITR);
}

/// parseTypeIdentifierOrTypeComposition
/// - Identifiers and compositions both start with the same identifier
///   token, parse it and continue constructing a composition if the
///   next token is '&'
///
///   type-composition:
///     type-identifier ('&' type-identifier)*
///     'protocol' '<' type-composition-list-deprecated? '>'
///
///   type-composition-list-deprecated:
///     type-identifier (',' type-identifier)*
ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {

  // Handle deprecated case
  if (Tok.getKind() == tok::kw_protocol && startsWithLess(peekToken())) {
    SourceLoc ProtocolLoc = consumeToken(tok::kw_protocol);
    SourceLoc LAngleLoc = consumeStartingLess();

    // Parse the type-composition-list.
    ParserStatus Status;
    SmallVector<IdentTypeRepr *, 4> Protocols;
    bool IsEmpty = startsWithGreater(Tok);
    if (!IsEmpty) {
      do {
        // Parse the type-identifier.
        ParserResult<TypeRepr> Protocol = parseTypeIdentifier();
        Status |= Protocol;
        if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(
                                                       Protocol.getPtrOrNull()))
          Protocols.push_back(ident);
      } while (consumeIf(tok::comma));
    }

    // Check for the terminating '>'.
    SourceLoc RAngleLoc = PreviousLoc;
    if (startsWithGreater(Tok)) {
      RAngleLoc = consumeStartingGreater();
    } else {
      if (Status.isSuccess()) {
        diagnose(Tok, diag::expected_rangle_protocol);
        diagnose(LAngleLoc, diag::opening_angle);
        Status.setIsParseError();
      }

      // Skip until we hit the '>'.
      RAngleLoc = skipUntilGreaterInTypeList(/*protocolComposition=*/true);
    }

    auto composition = ProtocolCompositionTypeRepr::create(
      Context, Protocols, ProtocolLoc, {LAngleLoc, RAngleLoc});

    if (Status.isSuccess()) {
      // Only if we have complete protocol<...> construct, diagnose deprecated.

      SmallString<32> replacement;
      if (Protocols.empty()) {
        replacement = "Any";
      } else {
        auto extractText = [&](IdentTypeRepr *Ty) -> StringRef {
          auto SourceRange = Ty->getSourceRange();
          return SourceMgr.extractText(
            Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange));
        };
        auto Begin = Protocols.begin();
        replacement += extractText(*Begin);
        while (++Begin != Protocols.end()) {
          replacement += " & ";
          replacement += extractText(*Begin);
        }
      }

      // Copy trailing content after '>' to the replacement string.
      // FIXME: lexer should smartly separate '>' and trailing contents like '?'.
      StringRef TrailingContent = L->getTokenAt(RAngleLoc).getRange().str().
        substr(1);
      if (!TrailingContent.empty()) {
        if (Protocols.size() > 1) {
          replacement.insert(replacement.begin(), '(');
          replacement += ")";
        }
        replacement += TrailingContent;
      }

      // Replace 'protocol<T1, T2>' with 'T1 & T2'
      diagnose(ProtocolLoc,
        IsEmpty              ? diag::deprecated_any_composition :
        Protocols.size() > 1 ? diag::deprecated_protocol_composition :
                               diag::deprecated_protocol_composition_single)
        .highlight(composition->getSourceRange())
        .fixItReplace(composition->getSourceRange(), replacement);
    }

    return makeParserResult(Status, composition);
  }

  SourceLoc FirstTypeLoc = Tok.getLoc();

  // Parse the first type
  ParserResult<TypeRepr> FirstType = parseTypeIdentifier();
  if (!Tok.isContextualPunctuator("&"))
    return FirstType;

  SmallVector<IdentTypeRepr *, 4> Protocols;
  ParserStatus Status;

  // If it is not 'Any', add it to the protocol list
  if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(FirstType.getPtrOrNull()))
    Protocols.push_back(ident);
  Status |= FirstType;
  auto FirstAmpersandLoc = Tok.getLoc();

  while (Tok.isContextualPunctuator("&")) {
    consumeToken(); // consume '&'
    ParserResult<TypeRepr> Protocol = parseTypeIdentifier();
    Status |= Protocol;
    if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(Protocol.getPtrOrNull()))
      Protocols.push_back(ident);
  };

  return makeParserResult(Status, ProtocolCompositionTypeRepr::create(
    Context, Protocols, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc}));
}

ParserResult<ProtocolCompositionTypeRepr> Parser::parseAnyType() {
  return makeParserResult(ProtocolCompositionTypeRepr
    ::createEmptyComposition(Context, consumeToken(tok::kw_Any)));
}

/// parseTypeTupleBody
///   type-tuple:
///     '(' type-tuple-body? ')'
///   type-tuple-body:
///     type-tuple-element (',' type-tuple-element)* '...'?
///   type-tuple-element:
///     identifier ':' type
///     type
ParserResult<TupleTypeRepr> Parser::parseTypeTupleBody() {
  Parser::StructureMarkerRAII ParsingTypeTuple(*this, Tok);
  SourceLoc RPLoc, LPLoc = consumeToken(tok::l_paren);
  SourceLoc EllipsisLoc;
  unsigned EllipsisIdx;
  SmallVector<TypeRepr *, 8> ElementsR;

  // We keep track of the labels separately, and apply them at the end.
  SmallVector<std::tuple<Identifier, SourceLoc, Identifier, SourceLoc>, 4>
    Labels;

  ParserStatus Status = parseList(tok::r_paren, LPLoc, RPLoc,
                                  tok::comma, /*OptionalSep=*/false,
                                  /*AllowSepAfterLast=*/false,
                                  diag::expected_rparen_tuple_type_list,
                                  [&] () -> ParserStatus {
    // If this is a deprecated use of the inout marker in an argument list,
    // consume the inout.
    SourceLoc InOutLoc;
    bool hasAnyInOut = false;
    bool hasValidInOut = false;
    if (consumeIf(tok::kw_inout, InOutLoc)) {
      hasAnyInOut = true;
      hasValidInOut = false;
    }
    // If the tuple element starts with a potential argument label followed by a
    // ':' or another potential argument label, then the identifier is an
    // element tag, and it is followed by a type annotation.
    if (Tok.canBeArgumentLabel() &&
        (peekToken().is(tok::colon) || peekToken().canBeArgumentLabel())) {
      // Consume the name
      Identifier name;
      if (!Tok.is(tok::kw__))
        name = Context.getIdentifier(Tok.getText());
      SourceLoc nameLoc = consumeToken();

      // If there is a second name, consume it as well.
      Identifier secondName;
      SourceLoc secondNameLoc;
      if (Tok.canBeArgumentLabel()) {
        if (!Tok.is(tok::kw__))
          secondName = Context.getIdentifier(Tok.getText());
        secondNameLoc = consumeToken();
      }

      // Consume the ':'.
      if (!consumeIf(tok::colon))
        diagnose(Tok, diag::expected_parameter_colon);

      SourceLoc postColonLoc = Tok.getLoc();

      // Consume 'inout' if present.
      if (!hasAnyInOut && consumeIf(tok::kw_inout, InOutLoc)) {
        hasValidInOut = true;
      }

      SourceLoc extraneousInOutLoc;
      while (consumeIf(tok::kw_inout, extraneousInOutLoc)) {
        diagnose(Tok, diag::parameter_inout_var_let_repeated)
          .fixItRemove(extraneousInOutLoc);
      }

      // Parse the type annotation.
      ParserResult<TypeRepr> type = parseType(diag::expected_type);
      if (type.hasCodeCompletion())
        return makeParserCodeCompletionStatus();
      if (type.isNull())
        return makeParserError();

      if (!hasValidInOut && hasAnyInOut) {
        diagnose(Tok.getLoc(), diag::inout_as_attr_disallowed)
          .fixItRemove(InOutLoc)
          .fixItInsert(postColonLoc, "inout ");
      }

      // If an 'inout' marker was specified, build the type.  Note that we bury
      // the inout locator within the named locator.  This is weird but required
      // by sema apparently.
      if (InOutLoc.isValid())
        type = makeParserResult(new (Context) InOutTypeRepr(type.get(),
                                                            InOutLoc));

      // Record the label. We will look at these at the end.
      if (Labels.empty()) {
        Labels.assign(ElementsR.size(),
                      std::make_tuple(Identifier(), SourceLoc(),
                                      Identifier(), SourceLoc()));
      }
      Labels.push_back(std::make_tuple(name, nameLoc,
                                       secondName, secondNameLoc));

      ElementsR.push_back(type.get());
    } else {
      // Otherwise, this has to be a type.
      ParserResult<TypeRepr> type = parseType();
      if (type.hasCodeCompletion())
        return makeParserCodeCompletionStatus();
      if (type.isNull())
        return makeParserError();
      if (InOutLoc.isValid())
        type = makeParserResult(new (Context) InOutTypeRepr(type.get(),
                                                            InOutLoc));

      if (!Labels.empty()) {
        Labels.push_back(std::make_tuple(Identifier(), SourceLoc(),
                                         Identifier(), SourceLoc()));
      }

      ElementsR.push_back(type.get());
    }

    // Parse '= expr' here so we can complain about it directly, rather
    // than dying when we see it.
    if (Tok.is(tok::equal)) {
      SourceLoc equalLoc = consumeToken(tok::equal);
      auto init = parseExpr(diag::expected_init_value);
      auto inFlight = diagnose(equalLoc, diag::tuple_type_init);
      if (init.isNonNull())
        inFlight.fixItRemove(SourceRange(equalLoc, init.get()->getEndLoc()));
    }

    if (Tok.isEllipsis()) {
      if (EllipsisLoc.isValid()) {
        diagnose(Tok, diag::multiple_ellipsis_in_tuple)
          .highlight(EllipsisLoc)
          .fixItRemove(Tok.getLoc());
        (void)consumeToken();
      } else {
        EllipsisLoc = consumeToken();
        EllipsisIdx = ElementsR.size() - 1;
      }
    }
    return makeParserSuccess();
  });

  if (EllipsisLoc.isValid() && ElementsR.empty()) {
    EllipsisLoc = SourceLoc();
  }

  if (EllipsisLoc.isInvalid())
    EllipsisIdx = ElementsR.size();

  // If there were any labels, figure out which labels should go into the type
  // representation.
  if (!Labels.empty()) {
    assert(Labels.size() == ElementsR.size());
    bool isFunctionType = Tok.isAny(tok::arrow, tok::kw_throws,
                                    tok::kw_rethrows);
    for (unsigned i : indices(ElementsR)) {
      auto &currentLabel = Labels[i];

      Identifier firstName = std::get<0>(currentLabel);
      SourceLoc firstNameLoc = std::get<1>(currentLabel);
      Identifier secondName = std::get<2>(currentLabel);
      SourceLoc secondNameLoc = std::get<3>(currentLabel);

      // True tuples have labels.
      if (!isFunctionType) {
        // If there were two names, complain.
        if (firstNameLoc.isValid() && secondNameLoc.isValid()) {
          auto diag = diagnose(firstNameLoc, diag::tuple_type_multiple_labels);
          if (firstName.empty()) {
            diag.fixItRemoveChars(firstNameLoc, ElementsR[i]->getStartLoc());
          } else {
            diag.fixItRemove(
              SourceRange(Lexer::getLocForEndOfToken(SourceMgr,firstNameLoc),
                          secondNameLoc));
          }
        }

        // Form the named type representation.
        ElementsR[i] = new (Context) NamedTypeRepr(firstName, ElementsR[i],
                                                   firstNameLoc);
        continue;
      }

      // If there was a first name, complain; arguments in function types are
      // always unlabeled.
      if (firstNameLoc.isValid() && !firstName.empty()) {
        auto diag = diagnose(firstNameLoc, diag::function_type_argument_label,
                             firstName);
        if (secondNameLoc.isInvalid())
          diag.fixItInsert(firstNameLoc, "_ ");
        else if (secondName.empty())
          diag.fixItRemoveChars(firstNameLoc, ElementsR[i]->getStartLoc());
        else
          diag.fixItReplace(SourceRange(firstNameLoc), "_");
      }

      if (firstNameLoc.isValid() || secondNameLoc.isValid()) {
        // Form the named parameter type representation.
        ElementsR[i] = new (Context) NamedTypeRepr(secondName, ElementsR[i],
                                                   secondNameLoc, firstNameLoc);
      }
    }
  }

  return makeParserResult(Status,
                          TupleTypeRepr::create(Context, ElementsR,
                                                SourceRange(LPLoc, RPLoc),
                                                EllipsisLoc, EllipsisIdx));
}

/// parseTypeArray - Parse the type-array production, given that we
/// are looking at the initial l_square.  Note that this index
/// clause is actually the outermost (first-indexed) clause.
///
///   type-array:
///     type-simple
///     type-array '[' ']'
///     type-array '[' expr ']'
///
ParserResult<TypeRepr> Parser::parseTypeArray(TypeRepr *Base) {
  assert(Tok.isFollowingLSquare());
  Parser::StructureMarkerRAII ParsingArrayBound(*this, Tok);
  SourceLoc lsquareLoc = consumeToken();
  ArrayTypeRepr *ATR = nullptr;

  // Handle a postfix [] production, a common typo for a C-like array.

  // If we have something that might be an array size expression, parse it as
  // such, for better error recovery.
  if (Tok.isNot(tok::r_square)) {
    auto sizeEx = parseExprBasic(diag::expected_expr);
    if (sizeEx.hasCodeCompletion())
      return makeParserCodeCompletionStatus();
    if (sizeEx.isNull())
      return makeParserErrorResult(Base);
  }

  SourceLoc rsquareLoc;
  if (parseMatchingToken(tok::r_square, rsquareLoc,
                         diag::expected_rbracket_array_type, lsquareLoc))
    return makeParserErrorResult(Base);

  // If we parsed something valid, diagnose it with a fixit to rewrite it to
  // Swift syntax.
  diagnose(lsquareLoc, diag::new_array_syntax)
    .fixItInsert(Base->getStartLoc(), "[")
    .fixItRemove(lsquareLoc);

  // Build a normal array slice type for recovery.
  ATR = new (Context) ArrayTypeRepr(Base,
                              SourceRange(Base->getStartLoc(), rsquareLoc));
  return makeParserResult(ATR);
}

ParserResult<TypeRepr> Parser::parseTypeCollection() {
  // Parse the leading '['.
  assert(Tok.is(tok::l_square));
  Parser::StructureMarkerRAII parsingCollection(*this, Tok);
  SourceLoc lsquareLoc = consumeToken();

  // Parse the element type.
  ParserResult<TypeRepr> firstTy = parseType(diag::expected_element_type);

  // If there is a ':', this is a dictionary type.
  SourceLoc colonLoc;
  ParserResult<TypeRepr> secondTy;
  if (Tok.is(tok::colon)) {
    colonLoc = consumeToken();

    // Parse the second type.
    secondTy = parseType(diag::expected_dictionary_value_type);
  }

  // Parse the closing ']'.
  SourceLoc rsquareLoc;
  parseMatchingToken(tok::r_square, rsquareLoc,
                     colonLoc.isValid()
                       ? diag::expected_rbracket_dictionary_type
                       : diag::expected_rbracket_array_type,
                     lsquareLoc);

  if (firstTy.hasCodeCompletion() || secondTy.hasCodeCompletion())
    return makeParserCodeCompletionStatus();

  // If we couldn't parse anything for one of the types, propagate the error.
  if (firstTy.isNull() || (colonLoc.isValid() && secondTy.isNull()))
    return makeParserError();

  // Form the dictionary type.
  SourceRange brackets(lsquareLoc, rsquareLoc);
  if (colonLoc.isValid())
    return makeParserResult(ParserStatus(firstTy) | ParserStatus(secondTy),
                            new (Context) DictionaryTypeRepr(firstTy.get(),
                                                             secondTy.get(),
                                                             colonLoc,
                                                             brackets));

  // Form the array type.
  return makeParserResult(firstTy,
                          new (Context) ArrayTypeRepr(firstTy.get(),
                                                      brackets));
}

bool Parser::isOptionalToken(const Token &T) const {
  // A postfix '?' by itself is obviously optional.
  if (T.is(tok::question_postfix))
    return true;

  // A postfix or bound infix operator token that begins with '?' can be
  // optional too. We'll munch off the '?', so long as it is left-bound with
  // the type (i.e., parsed as a postfix or unspaced binary operator).
  if ((T.is(tok::oper_postfix) || T.is(tok::oper_binary_unspaced)) &&
      T.getText().startswith("?"))
    return true;
  return false;
}

bool Parser::isImplicitlyUnwrappedOptionalToken(const Token &T) const {
  // A postfix '!' by itself, or a '!' in SIL mode, is obviously implicitly
  // unwrapped optional.
  if (T.is(tok::exclaim_postfix) || T.is(tok::sil_exclamation))
    return true;
  // A postfix or bound infix operator token that begins with '!' can be
  // implicitly unwrapped optional too. We'll munch off the '!', so long as it
  // is left-bound with the type (i.e., parsed as a postfix or unspaced binary
  // operator).
  if ((T.is(tok::oper_postfix) || T.is(tok::oper_binary_unspaced)) &&
      T.getText().startswith("!"))
    return true;
  return false;
}

SourceLoc Parser::consumeOptionalToken() {
  assert(isOptionalToken(Tok) && "not a '?' token?!");
  return consumeStartingCharacterOfCurrentToken();
}

SourceLoc Parser::consumeImplicitlyUnwrappedOptionalToken() {
  assert(isImplicitlyUnwrappedOptionalToken(Tok) && "not a '!' token?!");
  // If the text of the token is just '!', grab the next token.
  return consumeStartingCharacterOfCurrentToken();
}

/// Parse a single optional suffix, given that we are looking at the
/// question mark.
ParserResult<OptionalTypeRepr> Parser::parseTypeOptional(TypeRepr *base) {
  SourceLoc questionLoc = consumeOptionalToken();
  return makeParserResult(new (Context) OptionalTypeRepr(base, questionLoc));
}

/// Parse a single implicitly unwrapped optional suffix, given that we
/// are looking at the exclamation mark.
ParserResult<ImplicitlyUnwrappedOptionalTypeRepr>
Parser::parseTypeImplicitlyUnwrappedOptional(TypeRepr *base) {
  SourceLoc exclamationLoc = consumeImplicitlyUnwrappedOptionalToken();
  return makeParserResult(
           new (Context) ImplicitlyUnwrappedOptionalTypeRepr(
                           base, exclamationLoc));
}

//===----------------------------------------------------------------------===//
// Speculative type list parsing
//===----------------------------------------------------------------------===//

static bool isGenericTypeDisambiguatingToken(Parser &P) {
  auto &tok = P.Tok;
  switch (tok.getKind()) {
  default:
    return false;
  case tok::r_paren:
  case tok::r_square:
  case tok::l_brace:
  case tok::r_brace:
  case tok::period:
  case tok::period_prefix:
  case tok::comma:
  case tok::semi:
  case tok::eof:
  case tok::code_complete:
  case tok::exclaim_postfix:
  case tok::question_postfix:
    return true;

  case tok::oper_binary_unspaced:
  case tok::oper_binary_spaced:
  case tok::oper_postfix:
    // These might be '?' or '!' type modifiers.
    return P.isOptionalToken(tok) || P.isImplicitlyUnwrappedOptionalToken(tok);

  case tok::l_paren:
  case tok::l_square:
    // These only apply to the generic type if they don't start a new line.
    return !tok.isAtStartOfLine();
  }
}

bool Parser::canParseAsGenericArgumentList() {
  if (!Tok.isAnyOperator() || !Tok.getText().equals("<"))
    return false;

  BacktrackingScope backtrack(*this);

  if (canParseGenericArguments())
    return isGenericTypeDisambiguatingToken(*this);

  return false;
}

bool Parser::canParseGenericArguments() {
  // Parse the opening '<'.
  if (!startsWithLess(Tok))
    return false;
  consumeStartingLess();

  do {
    if (!canParseType())
      return false;
    // Parse the comma, if the list continues.
  } while (consumeIf(tok::comma));

  if (!startsWithGreater(Tok)) {
    return false;
  } else {
    consumeStartingGreater();
    return true;
  }
}

bool Parser::canParseType() {
  switch (Tok.getKind()) {
  case tok::kw_Self:
  case tok::kw_Any:
      if (!canParseTypeIdentifier())
        return false;
      break;
  case tok::kw_protocol: // Deprecated composition syntax
  case tok::identifier:
    if (!canParseTypeIdentifierOrTypeComposition())
      return false;
    break;
  case tok::l_paren: {
    consumeToken();
    if (!canParseTypeTupleBody())
      return false;
    break;
  }
  case tok::at_sign: {
    consumeToken();
    if (!canParseTypeAttribute())
      return false;
    return canParseType();
  }
  case tok::l_square:
    consumeToken();
    if (!canParseType())
      return false;
    if (consumeIf(tok::colon)) {
      if (!canParseType())
        return false;
    }
    if (!consumeIf(tok::r_square))
      return false;
    break;

  default:
    return false;
  }

  // '.Type', '.Protocol', '?', and '!' still leave us with type-simple.
  while (true) {
    if ((Tok.is(tok::period) || Tok.is(tok::period_prefix)) &&
        (peekToken().isContextualKeyword("Type")
         || peekToken().isContextualKeyword("Protocol"))) {
      consumeToken();
      consumeToken(tok::identifier);
      continue;
    }
    if (isOptionalToken(Tok)) {
      consumeOptionalToken();
      continue;
    }
    if (isImplicitlyUnwrappedOptionalToken(Tok)) {
      consumeImplicitlyUnwrappedOptionalToken();
      continue;
    }
    break;
  }

  // Handle type-function if we have an arrow or 'throws'/'rethrows' modifier.
  if (Tok.isAny(tok::kw_throws, tok::kw_rethrows)) {
    consumeToken();
    // "throws" or "rethrows" isn't a valid type without being followed by
    // a return.
    if (!Tok.is(tok::arrow))
      return false;
  }

  if (consumeIf(tok::arrow)) {
    if (!canParseType())
      return false;
    return true;
  }

  return true;
}

bool Parser::canParseTypeIdentifierOrTypeComposition() {
  if (Tok.is(tok::kw_protocol))
    return canParseOldStyleProtocolComposition();

  while (true) {
    if (!canParseTypeIdentifier())
      return false;

    if (Tok.isContextualPunctuator("&")) {
      consumeToken();
      continue;
    } else {
      return true;
    }
  }
}

bool Parser::canParseTypeIdentifier() {
  while (true) {
    if (!Tok.isAny(tok::identifier, tok::kw_Self, tok::kw_Any))
      return false;
    consumeToken();

    if (startsWithLess(Tok)) {
      if (!canParseGenericArguments())
        return false;
    }

    // Treat 'Foo.<anything>' as an attempt to write a dotted type
    // unless <anything> is 'Type'.
    if ((Tok.is(tok::period) || Tok.is(tok::period_prefix)) &&
        !peekToken().isContextualKeyword("Type") &&
        !peekToken().isContextualKeyword("Protocol")) {
      consumeToken();
    } else {
      return true;
    }
  }
}

bool Parser::canParseOldStyleProtocolComposition() {
  consumeToken(tok::kw_protocol);

  // Check for the starting '<'.
  if (!startsWithLess(Tok)) {
    return false;
  }
  consumeStartingLess();

  // Check for empty protocol composition.
  if (startsWithGreater(Tok)) {
    consumeStartingGreater();
    return true;
  }

  // Parse the type-composition-list.
  do {
    if (!canParseTypeIdentifier()) {
      return false;
    }
  } while (consumeIf(tok::comma));

  // Check for the terminating '>'.
  if (!startsWithGreater(Tok)) {
    return false;
  }
  consumeStartingGreater();

  return true;
}

bool Parser::canParseTypeTupleBody() {
  if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::r_brace) &&
      Tok.isNotEllipsis() && !isStartOfDecl()) {
    do {
      // The contextual inout marker is part of argument lists.
      consumeIf(tok::kw_inout);

      // If the tuple element starts with "ident :", then it is followed
      // by a type annotation.
      if (Tok.canBeArgumentLabel() &&
          (peekToken().is(tok::colon) || peekToken().canBeArgumentLabel())) {
        consumeToken();
        if (Tok.canBeArgumentLabel()) {
          consumeToken();
          if (!Tok.is(tok::colon)) return false;
        }
        consumeToken(tok::colon);

        // Parse a type.
        if (!canParseType())
          return false;

        // Parse default values. This aren't actually allowed, but we recover
        // better if we skip over them.
        if (consumeIf(tok::equal)) {
          while (Tok.isNot(tok::eof) && Tok.isNot(tok::r_paren) &&
                 Tok.isNot(tok::r_brace) && Tok.isNotEllipsis() &&
                 Tok.isNot(tok::comma) &&
                 !isStartOfDecl()) {
            skipSingle();
          }
        }

        continue;
      }

      // Otherwise, this has to be a type.
      if (!canParseType())
        return false;

      if (Tok.isEllipsis())
        consumeToken();

    } while (consumeIf(tok::comma));
  }

  return consumeIf(tok::r_paren);
}


text:
namespace gfx {
class Insets;
}

namespace apps {

class SizeConstraints {
 public:
  // The value SizeConstraints uses to represent an unbounded width or height.
  // This is an enum so that it can be declared inline here.
  enum { kUnboundedSize = 0 };

  SizeConstraints();
  SizeConstraints(const gfx::Size& min_size, const gfx::Size& max_size);
  ~SizeConstraints();

  // Adds frame insets to a size constraint.
  static gfx::Size AddFrameToConstraints(const gfx::Size& size_constraints,
                                         const gfx::Insets& frame_insets);

  // Returns the bounds with its size clamped to the min/max size.
  gfx::Size ClampSize(gfx::Size size) const;

  // When gfx::Size is used as a min/max size, a zero represents an unbounded
  // component. This method checks whether either component is specified.
  // Note we can't use gfx::Size::IsEmpty as it returns true if either width
  // or height is zero.
  bool HasMinimumSize() const;
  bool HasMaximumSize() const;

  // This returns true if all components are specified, and min and max are
  // equal.
  bool HasFixedSize() const;

  gfx::Size GetMaximumSize() const;
  gfx::Size GetMinimumSize() const;

  void set_minimum_size(const gfx::Size& min_size);
  void set_maximum_size(const gfx::Size& max_size);

 private:
  gfx::Size minimum_size_;
  gfx::Size maximum_size_;
};

}  // namespace apps

#endif  // APPS_SIZE_CONSTRAINTS_H_

redpajama_set_name: RedPajamaGithub


text:
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
from django.core.exceptions import ImproperlyConfigured
from django.utils import importlib
from django.utils.encoding import smart_unicode, smart_str
from django.utils.datastructures import SortedDict

try:
    import cPickle as pickle
except ImportError:
    import pickle

try:
    import redis
except ImportError:
    raise InvalidCacheBackendError(
        "Redis cache backend requires the 'redis-py' library")
from redis.connection import UnixDomainSocketConnection, Connection
from redis.connection import DefaultParser

class CacheKey(object):
    """
    A stub string class that we can use to check if a key was created already.
    """
    def __init__(self, key):
        self._key = key

    def __eq__(self, other):
        return self._key == other

    def __str__(self):
        return self.__unicode__()

    def __repr__(self):
        return self.__unicode__()

    def __unicode__(self):
        return smart_str(self._key)

class CacheConnectionPool(object):

    def __init__(self):
        self._connection_pools = {}

    def get_connection_pool(self, host='127.0.0.1', port=6379, db=1,
        password=None, parser_class=None,
        unix_socket_path=None):
        connection_identifier = (host, port, db, parser_class, unix_socket_path)
        if not self._connection_pools.get(connection_identifier):
            connection_class = (
                unix_socket_path and UnixDomainSocketConnection or Connection
            )
            kwargs = {
                'db': db,
                'password': password,
                'connection_class': connection_class,
                'parser_class': parser_class,
            }
            if unix_socket_path is None:
                kwargs.update({
                    'host': host,
                    'port': port,
                })
            else:
                kwargs['path'] = unix_socket_path
            self._connection_pools[connection_identifier] = redis.ConnectionPool(**kwargs)
        return self._connection_pools[connection_identifier]
pool = CacheConnectionPool()

class CacheClass(BaseCache):
    def __init__(self, server, params):
        """
        Connect to Redis, and set up cache backend.
        """
        self._init(server, params)

    def _init(self, server, params):
        super(CacheClass, self).__init__(params)
        self._server = server
        self._params = params

        unix_socket_path = None
        if ':' in self.server:
            host, port = self.server.rsplit(':', 1)
            try:
                port = int(port)
            except (ValueError, TypeError):
                raise ImproperlyConfigured("port value must be an integer")
        else:
            host, port = None, None
            unix_socket_path = self.server

        kwargs = {
            'db': self.db,
            'password': self.password,
            'host': host,
            'port': port,
            'unix_socket_path': unix_socket_path,
        }
        connection_pool = pool.get_connection_pool(
            parser_class=self.parser_class,
            **kwargs
        )
        self._client = redis.Redis(
            connection_pool=connection_pool,
            **kwargs
        )

    @property
    def server(self):
        return self._server or "127.0.0.1:6379"

    @property
    def params(self):
        return self._params or {}

    @property
    def options(self):
        return self.params.get('OPTIONS', {})

    @property
    def db(self):
        _db = self.params.get('db', self.options.get('DB', 1))
        try:
            _db = int(_db)
        except (ValueError, TypeError):
            raise ImproperlyConfigured("db value must be an integer")
        return _db

    @property
    def password(self):
        return self.params.get('password', self.options.get('PASSWORD', None))

    @property
    def parser_class(self):
        cls = self.options.get('PARSER_CLASS', None)
        if cls is None:
            return DefaultParser
        mod_path, cls_name = cls.rsplit('.', 1)
        try:
            mod = importlib.import_module(mod_path)
            parser_class = getattr(mod, cls_name)
        except (AttributeError, ImportError):
            raise ImproperlyConfigured("Could not find parser class '%s'" % parser_class)
        return parser_class

    def __getstate__(self):
        return {'params': self._params, 'server': self._server}

    def __setstate__(self, state):
        self._init(**state)

    def make_key(self, key, version=None):
        """
        Returns the utf-8 encoded bytestring of the given key as a CacheKey
        instance to be able to check if it was "made" before.
        """
        if not isinstance(key, CacheKey):
            key = CacheKey(key)
        return key

    def add(self, key, value, timeout=None, version=None):
        """
        Add a value to the cache, failing if the key already exists.

        Returns ``True`` if the object was added, ``False`` if not.
        """
        key = self.make_key(key, version=version)
        if self._client.exists(key):
            return False
        return self.set(key, value, timeout)

    def get(self, key, default=None, version=None):
        """
        Retrieve a value from the cache.

        Returns unpickled value if key is found, the default if not.
        """
        key = self.make_key(key, version=version)
        value = self._client.get(key)
        if value is None:
            return default
        try:
            result = int(value)
        except (ValueError, TypeError):
            result = self.unpickle(value)
        return result

    def hget(self, name, key, default=None, version=None):
        """
        Retrieve a value from the cache as hash.

        Returns unpickled value if key is found, the default if not.
        """
        name = self.make_key(name, version=version)
        key = self.make_key(key, version=version)
        value = self._client.hget(name, key)
        if value is None:
            return default
        try:
            result = int(value)
        except (ValueError, TypeError):
            result = self.unpickle(value)
        return result

    def _set(self, key, value, timeout, client):
        if timeout == 0:
            return client.set(key, value)
        elif timeout > 0:
            return client.setex(key, value, int(timeout))
        else:
            return False

    def _hset(self, name, key, value, timeout, client):
        """Set value in hash"""
        # Redis call
        status = client.hset( name, key, value)
        if timeout > 0:
            # Set expire time
            client.expire(name, timeout)
        return status

    def set(self, key, value, timeout=None, version=None, client=None):
        """
        Persist a value to the cache, and set an optional expiration time.
        """
        if not client:
            client = self._client
        key = self.make_key(key, version=version)
        if timeout is None:
            timeout = self.default_timeout
        try:
            value = float(value)
            # If you lose precision from the typecast to str, then pickle value
            if int(value) != value:
                raise TypeError
        except (ValueError, TypeError):
            result = self._set(key, pickle.dumps(value), int(timeout), client)
        else:
            result = self._set(key, int(value), int(timeout), client)
        # result is a boolean
        return result

    def hset(self, name, key, value, timeout=None, version=None, client=None):
        """
        Sets field in the hash stored at key to value
        and set an optional expiration time.
        """
        if not client:
            client = self._client
        name = self.make_key(name, version=version)
        key = self.make_key(key, version=version)
        if timeout is None:
            # To store it persistently
            timeout = 0
        try:
            value = float(value)
            # If you lose precision from the typecast to str, then pickle value
            if int(value) != value:
                raise TypeError
        except (ValueError, TypeError):
            result = self._hset(name, key, pickle.dumps(value), int(timeout), client)
        else:
            result = self._hset(name, key, int(value), int(timeout), client)
        # result is a boolean
        return result

    def delete(self, key, version=None):
        """
        Remove a key from the cache.
        """
        self._client.delete(self.make_key(key, version=version))

    def delete_many(self, keys, version=None):
        """
        Remove multiple keys at once.
        """
        if keys:
            keys = map(lambda key: self.make_key(key, version=version), keys)
            self._client.delete(*keys)

    def clear(self):
        """
        Flush all cache keys.
        """
        # TODO : potential data loss here, should we only delete keys based on the correct version ?
        self._client.flushdb()

    def unpickle(self, value):
        """
        Unpickles the given value.
        """
        value = smart_str(value)
        return pickle.loads(value)

    def get_many(self, keys, version=None):
        """
        Retrieve many keys.
        """
        if not keys:
            return {}
        recovered_data = SortedDict()
        new_keys = map(lambda key: self.make_key(key, version=version), keys)
        map_keys = dict(zip(new_keys, keys))
        results = self._client.mget(new_keys)
        for key, value in zip(new_keys, results):
            if value is None:
                continue
            try:
                value = int(value)
            except (ValueError, TypeError):
                value = self.unpickle(value)
            if isinstance(value, basestring):
                value = smart_unicode(value)
            recovered_data[map_keys[key]] = value
        return recovered_data

    def hget_many(self, name, keys, version=None):
        """
        Retrieve many keys from hash.
        Keys is the list of the key in the hash.
        Result is returned as key value pair dict.
        """
        recovered_data = SortedDict()
        new_keys = map(lambda key: self.make_key(key, version=version), keys)
        map_keys = dict(zip(new_keys, keys))
        name = self.make_key(name, version=version)
        # Redis call
        results = self._client.hmget(name, new_keys)
        # Iterate to convert the result into proper format.
        for key, value in zip(new_keys, results):
            if value is None:
                continue
            try:
                value = int(value)
            except (ValueError, TypeError):
                value = self.unpickle(value)
            if isinstance(value, basestring):
                value = smart_unicode(value)
            recovered_data[map_keys[key]] = value
        return recovered_data

    def set_many(self, data, timeout=None, version=None):
        """
        Set a bunch of values in the cache at once from a dict of key/value
        pairs. This is much more efficient than calling set() multiple times.

        If timeout is given, that timeout will be used for the key; otherwise
        the default cache timeout will be used.
        """
        pipeline = self._client.pipeline()
        for key, value in data.iteritems():
            self.set(key, value, timeout, version=version, client=pipeline)
        pipeline.execute()

    def hset_many(self, name, mapping_dict, timeout=None, version=None):
        """
        Set a bunch of values in the cache at once from a dict of key/value
        pairs. This is much more efficient than calling hset() multiple times.

        If timeout is given, that timeout will be used for the key; otherwise
        stored persistently
        """
        # Convert the keys to version format
        mapping_dict = dict( (self.make_key(key, version), value) for key, value in  mapping_dict.items() )
        name = self.make_key(name, version=version)
        # Iterate to convert the values to appropriate format.
        for key, value in mapping_dict.items():
            try:
                value = float(value)
                # If you lose precision from the typecast to str, then pickle value
                if int(value) != value:
                    raise TypeError
            except (ValueError, TypeError):
                value = pickle.dumps(value)
            else:
                value = int(value)
            mapping_dict[key] = value

        # Redis call
        result = self._client.hmset(name, mapping_dict)
        if timeout is not None:
            # Set timeout of the name
            self._client.expire(name, timeout)
        return result

    def incr(self, key, delta=1, version=None):
        """
        Add delta to value in the cache. If the key does not exist, raise a
        ValueError exception.
        """
        key = self.make_key(key, version=version)
        exists = self._client.exists(key)
        if not exists:
            raise ValueError("Key '%s' not found" % key)
        try:
            value = self._client.incr(key, delta)
        except redis.ResponseError:
            value = self.get(key) + 1
            self.set(key, value)
        return value

    def hincr(self, name, key, delta=1, version=None):
        """
        Add delta to value in the cache of the hash.
        If the key does not exist, raise a
        ValueError exception.
        """
        name = self.make_key(name, version=version)
        key = self.make_key(key, version=version)
        exists = self._client.hexists(name, key)
        if not exists:
            raise ValueError("Key '%s' not found" % key)
        try:
            # Redis call
            value = self._client.hincrby(name, key, delta)
        except redis.ResponseError:
            value = self.hget(name, key) + 1
            # Redis call
            self.hset(name, key, value)
        return value

    def has_hkey(self, name, key, version=None):
        """
        The name and key exist in the hash
        """
        name = self.make_key(name, version=version)
        key = self.make_key(key, version=version)
        return self._client.hexists(name, key)

class RedisCache(CacheClass):
    """
    A subclass that is supposed to be used on Django >= 1.3.
    """

    def make_key(self, key, version=None):
        if not isinstance(key, CacheKey):
            key = CacheKey(super(CacheClass, self).make_key(key, version))
        return key

    def incr_version(self, key, delta=1, version=None):
        """
        Adds delta to the cache version for the supplied key. Returns the
        new version.

        Note: In Redis 2.0 you cannot rename a volitle key, so we have to move
        the value from the old key to the new key and maintain the ttl.
        """
        if version is None:
            version = self.version
        old_key = self.make_key(key, version)
        value = self.get(old_key, version=version)
        ttl = self._client.ttl(old_key)
        if value is None:
            raise ValueError("Key '%s' not found" % key)
        new_key = self.make_key(key, version=version+delta)
        # TODO: See if we can check the version of Redis, since 2.2 will be able
        # to rename volitile keys.
        self.set(new_key, value, timeout=ttl)
        self.delete(old_key)
        return version + delta